Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tratar Erros da API como Notificações #644

Merged
merged 2 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions api/src/main/kotlin/nebulosa/api/Nebulosa.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ import com.fasterxml.jackson.module.kotlin.jsonMapper
import com.github.rvesse.airline.annotations.Command
import com.github.rvesse.airline.annotations.Option
import io.javalin.Javalin
import io.javalin.http.Context
import io.javalin.http.HttpStatus.BAD_REQUEST
import io.javalin.json.JavalinJackson
import nebulosa.api.converters.modules.DeviceModule
import nebulosa.api.core.ErrorResponse
import nebulosa.api.inject.*
import nebulosa.json.PathModule
import nebulosa.log.i
import nebulosa.log.loggerFor
import org.koin.core.context.startKoin
import org.slf4j.LoggerFactory
import java.net.ConnectException

@Command(name = "nebulosa")
class Nebulosa : Runnable, AutoCloseable {
Expand Down Expand Up @@ -52,6 +56,8 @@ class Nebulosa : Runnable, AutoCloseable {
}
}.start(host, port)

app.exception(Exception::class.java, ::handleException)

koinApp.modules(appModule(app))
koinApp.modules(objectMapperModule(OBJECT_MAPPER))
koinApp.modules(servicesModule())
Expand All @@ -61,6 +67,16 @@ class Nebulosa : Runnable, AutoCloseable {
LOG.i("server is started at port: {}", app.port())
}

private fun handleException(ex: Exception, ctx: Context) {
val message = when (ex) {
is ConnectException -> "connection refused"
is NumberFormatException -> "invalid number: ${ex.message}"
else -> ex.message!!
}

ctx.status(BAD_REQUEST).json(ErrorResponse.error(message.lowercase()))
}

override fun close() {
app.stop()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class SkyAtlasController(
}

private fun searchMinorPlanet(ctx: Context) {
val text = ctx.queryParam("text").notNull().notBlank()
val text = ctx.queryParam("text").notNullOrBlank()
ctx.json(skyAtlasService.searchMinorPlanet(text))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package nebulosa.api.confirmation
import io.javalin.Javalin
import io.javalin.http.Context
import nebulosa.api.core.Controller
import nebulosa.api.validators.notBlank
import nebulosa.api.validators.notNull
import nebulosa.api.validators.notNullOrBlank

class ConfirmationController(
override val app: Javalin,
Expand All @@ -16,7 +16,7 @@ class ConfirmationController(
}

private fun confirm(ctx: Context) {
val idempotencyKey = ctx.pathParam("idempotencyKey").notNull().notBlank()
val idempotencyKey = ctx.pathParam("idempotencyKey").notNullOrBlank()
val accepted = ctx.queryParam("accepted").notNull().toBoolean()
confirmationService.confirm(idempotencyKey, accepted)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package nebulosa.api.connection
import io.javalin.Javalin
import io.javalin.http.Context
import nebulosa.api.core.Controller
import nebulosa.api.validators.notBlank
import nebulosa.api.validators.notNull
import nebulosa.api.validators.notNullOrBlank
import nebulosa.api.validators.range

class ConnectionController(
Expand All @@ -20,7 +20,7 @@ class ConnectionController(
}

private fun connect(ctx: Context) {
val host = ctx.queryParam("host").notNull().notBlank()
val host = ctx.queryParam("host").notNullOrBlank()
val port = ctx.queryParam("port").notNull().toInt().range(1, 65535)
val type = ctx.queryParam("type").notNull().let(ConnectionType::valueOf)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package nebulosa.api.connection

import io.javalin.http.InternalServerErrorResponse
import nebulosa.alpaca.indi.client.AlpacaClient
import nebulosa.api.message.MessageService
import nebulosa.indi.client.INDIClient
Expand Down Expand Up @@ -81,7 +80,7 @@ class ConnectionService(
return provider.id
} catch (e: Throwable) {
LOG.e("failed to connect", e)
throw InternalServerErrorResponse("Connection Failed")
throw e
}
}

Expand Down
20 changes: 20 additions & 0 deletions api/src/main/kotlin/nebulosa/api/core/ErrorResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package nebulosa.api.core

import nebulosa.api.notification.Severity

data class ErrorResponse(
@JvmField val type: Severity,
@JvmField val message: String,
) {

companion object {

fun success(message: String) = ErrorResponse(Severity.SUCCESS, message)

fun info(message: String) = ErrorResponse(Severity.INFO, message)

fun warn(message: String) = ErrorResponse(Severity.WARNING, message)

fun error(message: String) = ErrorResponse(Severity.ERROR, message)
}
}
7 changes: 3 additions & 4 deletions api/src/main/kotlin/nebulosa/api/framing/FramingController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import io.javalin.Javalin
import io.javalin.http.Context
import nebulosa.api.core.Controller
import nebulosa.api.image.ImageService
import nebulosa.api.validators.notBlank
import nebulosa.api.validators.notNull
import nebulosa.api.validators.notNullOrBlank
import nebulosa.api.validators.range
import nebulosa.math.deg
import nebulosa.math.hours
Expand All @@ -26,8 +25,8 @@ class FramingController(
}

private fun frame(ctx: Context) {
val rightAscension = ctx.queryParam("rightAscension").notNull().notBlank()
val declination = ctx.queryParam("declination").notNull().notBlank()
val rightAscension = ctx.queryParam("rightAscension").notNullOrBlank()
val declination = ctx.queryParam("declination").notNullOrBlank()
val width = ctx.queryParam("width")?.toInt()?.range(1, 7680) ?: 1280
val height = ctx.queryParam("height")?.toInt()?.range(1, 4320) ?: 720
val fov = ctx.queryParam("fov")?.toDouble()?.range(0.0, 90.0) ?: 1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import io.javalin.Javalin
import io.javalin.http.Context
import nebulosa.api.connection.ConnectionService
import nebulosa.api.core.Controller
import nebulosa.api.validators.notBlank
import nebulosa.api.validators.notNull
import nebulosa.api.validators.notNullOrBlank
import nebulosa.api.validators.range
import nebulosa.guiding.GuideDirection
import java.time.Duration
Expand Down Expand Up @@ -49,7 +49,7 @@ class GuideOutputController(
private fun pulse(ctx: Context) {
val id = ctx.pathParam("id")
val guideOutput = connectionService.guideOutput(id) ?: return
val direction = ctx.queryParam("direction").notNull().notBlank().let(GuideDirection::valueOf)
val direction = ctx.queryParam("direction").notNullOrBlank().let(GuideDirection::valueOf)
val duration = ctx.queryParam("duration").notNull().toLong().range(0L, 1800000000L).times(1000L).let(Duration::ofNanos)
guideOutputService.pulse(guideOutput, direction, duration)
}
Expand Down
3 changes: 1 addition & 2 deletions api/src/main/kotlin/nebulosa/api/image/ImageService.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package nebulosa.api.image

import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.http.NotFoundResponse
import jakarta.servlet.http.HttpServletResponse
import nebulosa.api.atlas.Location
import nebulosa.api.atlas.SimbadEntityRepository
Expand Down Expand Up @@ -280,7 +279,7 @@ class ImageService(
require(save.path != null)

var (image) = imageBucket.open(path).image?.transform(save.shouldBeTransformed, save.transformation, ImageOperation.SAVE)
?: throw NotFoundResponse("Image not found")
?: throw IllegalArgumentException("image not found")

val (x, y, width, height) = save.subFrame.constrained(image.width, image.height)

Expand Down
32 changes: 16 additions & 16 deletions api/src/main/kotlin/nebulosa/api/mounts/MountController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ class MountController(
private fun sync(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val rightAscension = ctx.queryParam("rightAscension").notNull().notBlank()
val declination = ctx.queryParam("declination").notNull().notBlank()
val rightAscension = ctx.queryParam("rightAscension").notNullOrBlank()
val declination = ctx.queryParam("declination").notNullOrBlank()
val j2000 = ctx.queryParam("j2000")?.toBoolean() ?: false
mountService.sync(mount, rightAscension.hours, declination.deg, j2000)
}

private fun slew(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val rightAscension = ctx.queryParam("rightAscension").notNull().notBlank()
val declination = ctx.queryParam("declination").notNull().notBlank()
val rightAscension = ctx.queryParam("rightAscension").notNullOrBlank()
val declination = ctx.queryParam("declination").notNullOrBlank()
val j2000 = ctx.queryParam("j2000")?.toBoolean() ?: false
val idempotencyKey = ctx.idempotencyKey()
mountService.slewTo(mount, rightAscension.hours, declination.deg, j2000, idempotencyKey)
Expand All @@ -98,8 +98,8 @@ class MountController(
private fun goTo(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val rightAscension = ctx.queryParam("rightAscension").notNull().notBlank()
val declination = ctx.queryParam("declination").notNull().notBlank()
val rightAscension = ctx.queryParam("rightAscension").notNullOrBlank()
val declination = ctx.queryParam("declination").notNullOrBlank()
val j2000 = ctx.queryParam("j2000")?.toBoolean() ?: false
val idempotencyKey = ctx.idempotencyKey()
mountService.goTo(mount, rightAscension.hours, declination.deg, j2000, idempotencyKey)
Expand All @@ -120,21 +120,21 @@ class MountController(
private fun trackMode(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val mode = ctx.queryParam("mode").notNull().notBlank().let(TrackMode::valueOf)
val mode = ctx.queryParam("mode").notNullOrBlank().let(TrackMode::valueOf)
mountService.trackMode(mount, mode)
}

private fun slewRate(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val rate = ctx.queryParam("rate").notNull().notBlank()
val rate = ctx.queryParam("rate").notNullOrBlank()
mountService.slewRate(mount, mount.slewRates.first { it.name == rate })
}

private fun move(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val direction = ctx.queryParam("direction").notNull().notBlank().let(GuideDirection::valueOf)
val direction = ctx.queryParam("direction").notNullOrBlank().let(GuideDirection::valueOf)
val enabled = ctx.queryParam("enabled").notNull().toBoolean()
mountService.move(mount, direction, enabled)
}
Expand All @@ -154,8 +154,8 @@ class MountController(
private fun coordinates(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val longitude = ctx.queryParam("longitude").notNull().notBlank()
val latitude = ctx.queryParam("latitude").notNull().notBlank()
val longitude = ctx.queryParam("longitude").notNullOrBlank()
val latitude = ctx.queryParam("latitude").notNullOrBlank()
val elevation = ctx.queryParam("elevation")?.toDouble() ?: 0.0
mountService.coordinates(mount, longitude.deg, latitude.deg, elevation.m)
}
Expand All @@ -173,7 +173,7 @@ class MountController(
private fun celestialLocation(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val type = ctx.pathParam("type").notNull().notBlank().let(CelestialLocationType::valueOf)
val type = ctx.pathParam("type").notNullOrBlank().let(CelestialLocationType::valueOf)

val location = when (type) {
CelestialLocationType.ZENITH -> mountService.computeZenithLocation(mount)
Expand All @@ -191,8 +191,8 @@ class MountController(
private fun location(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val rightAscension = ctx.queryParam("rightAscension").notNull().notBlank()
val declination = ctx.queryParam("declination").notNull().notBlank()
val rightAscension = ctx.queryParam("rightAscension").notNullOrBlank()
val declination = ctx.queryParam("declination").notNullOrBlank()
val j2000 = ctx.queryParam("j2000")?.toBoolean() ?: false
val equatorial = ctx.queryParam("equatorial")?.toBoolean() ?: true
val horizontal = ctx.queryParam("horizontal")?.toBoolean() ?: true
Expand All @@ -212,7 +212,7 @@ class MountController(
private fun remoteControlStart(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val protocol = ctx.queryParam("protocol").notNull().notBlank().let(MountRemoteControlProtocol::valueOf)
val protocol = ctx.queryParam("protocol").notNullOrBlank().let(MountRemoteControlProtocol::valueOf)
val host = ctx.queryParam("host")?.ifBlank { null } ?: "0.0.0.0"
val port = ctx.queryParam("port")?.toInt()?.positive() ?: 10001
mountService.remoteControlStart(mount, protocol, host, port)
Expand All @@ -221,7 +221,7 @@ class MountController(
private fun remoteControlStop(ctx: Context) {
val id = ctx.pathParam("id")
val mount = connectionService.mount(id) ?: return
val protocol = ctx.queryParam("protocol").notNull().notBlank().let(MountRemoteControlProtocol::valueOf)
val protocol = ctx.queryParam("protocol").notNullOrBlank().let(MountRemoteControlProtocol::valueOf)
mountService.remoteControlStop(mount, protocol)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import io.javalin.http.Context
import io.javalin.http.bodyAsClass
import nebulosa.api.core.Controller
import nebulosa.api.validators.exists
import nebulosa.api.validators.notNull
import nebulosa.api.validators.notNullOrBlank
import nebulosa.api.validators.path
import nebulosa.api.validators.valid

Expand All @@ -20,7 +20,7 @@ class PlateSolverController(
}

private fun start(ctx: Context) {
val path = ctx.queryParam("path")?.path().notNull().exists()
val path = ctx.queryParam("path").notNullOrBlank().path().exists()
val solver = ctx.bodyAsClass<PlateSolverRequest>().valid()
ctx.json(plateSolverService.solveImage(solver, path))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import nebulosa.api.converters.angle.DegreesDeserializer
import nebulosa.api.converters.angle.RightAscensionDeserializer
import nebulosa.api.converters.time.DurationUnit
import nebulosa.api.inject.Named
import nebulosa.api.validators.Validatable
import nebulosa.api.validators.max
import nebulosa.api.validators.positiveOrZero
import nebulosa.api.validators.*
import nebulosa.astap.platesolver.AstapPlateSolver
import nebulosa.astrometrynet.nova.NovaAstrometryNetService
import nebulosa.astrometrynet.platesolver.LocalAstrometryNetPlateSolver
Expand Down Expand Up @@ -44,6 +42,7 @@ data class PlateSolverRequest(
) : Validatable, KoinComponent, Supplier<PlateSolver> {

override fun validate() {
executablePath.notNull(PLATE_SOLVER_IS_NOT_CONFIGURED).notBlank(PLATE_SOLVER_IS_NOT_CONFIGURED)
timeout.positiveOrZero().max(5, TimeUnit.MINUTES)
downsampleFactor.positiveOrZero()
focalLength.positiveOrZero()
Expand All @@ -70,6 +69,8 @@ data class PlateSolverRequest(

companion object {

const val PLATE_SOLVER_IS_NOT_CONFIGURED = "plate solver is not configured"

@JvmStatic val EMPTY = PlateSolverRequest()
@JvmStatic private val NOVA_ASTROMETRY_NET_CACHE = HashMap<String, NovaAstrometryNetService>()
}
Expand Down
Loading