Skip to content

Commit ae08033

Browse files
committed
Rewrite image validation code into new patterns
1 parent 6046aa7 commit ae08033

4 files changed

Lines changed: 62 additions & 63 deletions

File tree

client/src/main/kotlin/org/dreamexposure/discal/client/commands/global/EventCommand.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import kotlinx.coroutines.reactor.awaitSingleOrNull
99
import org.dreamexposure.discal.client.commands.SlashCommand
1010
import org.dreamexposure.discal.core.business.CalendarService
1111
import org.dreamexposure.discal.core.business.EmbedService
12+
import org.dreamexposure.discal.core.business.ImageValidationService
1213
import org.dreamexposure.discal.core.business.PermissionService
1314
import org.dreamexposure.discal.core.enums.event.EventColor
1415
import org.dreamexposure.discal.core.enums.event.EventFrequency
1516
import org.dreamexposure.discal.core.`object`.event.Recurrence
1617
import org.dreamexposure.discal.core.`object`.new.Event
1718
import org.dreamexposure.discal.core.`object`.new.EventWizardState
1819
import org.dreamexposure.discal.core.`object`.new.GuildSettings
19-
import org.dreamexposure.discal.core.utils.ImageValidator
2020
import org.dreamexposure.discal.core.utils.getCommonMsg
2121
import org.springframework.stereotype.Component
2222
import java.time.*
@@ -28,6 +28,7 @@ class EventCommand(
2828
private val permissionService: PermissionService,
2929
private val calendarService: CalendarService,
3030
private val embedService: EmbedService,
31+
private val imageValidationService: ImageValidationService,
3132
) : SlashCommand {
3233
override val name = "event"
3334
override val hasSubcommands = true
@@ -447,7 +448,7 @@ class EventCommand(
447448
.awaitSingle()
448449

449450
// Check if provided link is actually an image we can consume
450-
val isValidImage = ImageValidator.validate(image, settings.patronGuild || settings.devGuild).awaitSingle()
451+
val isValidImage = imageValidationService.validate(image, settings.patronGuild || settings.devGuild)
451452
if (!isValidImage) return event.createFollowup(getMessage("image.failure", settings))
452453
.withEphemeral(ephemeral)
453454
.withEmbeds(embedService.eventWizardEmbed(existingWizard, settings))
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.dreamexposure.discal.core.business
2+
3+
import kotlinx.coroutines.Dispatchers
4+
import kotlinx.coroutines.withContext
5+
import org.springframework.stereotype.Component
6+
import java.io.FileNotFoundException
7+
import java.io.IOException
8+
import java.io.InputStream
9+
import java.net.MalformedURLException
10+
import java.net.URI
11+
import java.time.Duration
12+
import javax.imageio.ImageIO
13+
import javax.imageio.ImageReader
14+
15+
@Component
16+
class ImageValidationService {
17+
suspend fun validate(url: String, allowGif: Boolean): Boolean = withContext(Dispatchers.IO) {
18+
return@withContext try {
19+
val image = ImageIO.read(URI.create(url).toURL())
20+
image != null
21+
} catch (_: IOException) {
22+
if (allowGif) validateGif(url)
23+
else false
24+
} catch (_: MalformedURLException) {
25+
false
26+
} catch (_: FileNotFoundException) {
27+
false
28+
}
29+
}
30+
31+
private suspend fun validateGif(url: String): Boolean = withContext(Dispatchers.IO) {
32+
val connection = URI.create(url).toURL().openConnection()
33+
connection.connectTimeout = Duration.ofSeconds(3).toMillis().toInt()
34+
connection.readTimeout = Duration.ofSeconds(3).toMillis().toInt()
35+
36+
readGif(connection.inputStream)?.equals(".gif", true) == true
37+
}
38+
39+
private suspend fun readGif(input: InputStream): String? = withContext(Dispatchers.IO) {
40+
val stream = ImageIO.createImageInputStream(input)
41+
val iterator = ImageIO.getImageReaders(stream)
42+
if (!iterator.hasNext()) return@withContext null
43+
44+
var reader: ImageReader? = null
45+
try {
46+
reader = iterator.next()
47+
48+
reader.setInput(stream, true, true)
49+
reader.read(0, reader.defaultReadParam)
50+
} catch (_: Exception) {
51+
52+
} finally {
53+
reader?.dispose()
54+
}
55+
56+
reader?.formatName
57+
}
58+
}

core/src/main/kotlin/org/dreamexposure/discal/core/object/GuildSettings.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.dreamexposure.discal.core.serializers.SnowflakeAsStringSerializer
1010
import java.util.*
1111

1212
@Serializable
13+
@Deprecated("Prefer to use new.GuildSettings impl")
1314
data class GuildSettings(
1415
@Serializable(with = SnowflakeAsStringSerializer::class)
1516
@SerialName("guild_id")

core/src/main/kotlin/org/dreamexposure/discal/core/utils/ImageValidator.kt

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)