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

Remover Spring Boot #622

Merged
merged 31 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9b83a4e
[api]: Integrate with Javalin
tiagohm Oct 7, 2024
b9e846f
[api][desktop]: Refactor Connection Controller
tiagohm Oct 8, 2024
601ec7d
[api]: Refactor Confirmation Controller
tiagohm Oct 8, 2024
26325ad
[api]: Refactor Rotator Controller
tiagohm Oct 8, 2024
597a6a5
[api]: Refactor Focuser Controller
tiagohm Oct 8, 2024
0c4b59d
[api]: Refactor Wheel Controller
tiagohm Oct 8, 2024
cefad91
[api]: Refactor Light Box Controller
tiagohm Oct 8, 2024
271710d
[api]: Refactor Dust Cap Controller
tiagohm Oct 8, 2024
1e71106
[api]: Refactor Guide Output Controller
tiagohm Oct 8, 2024
4e90fc8
[api]: Refactor Plate Solver Controller
tiagohm Oct 8, 2024
3e0d7ad
[api]: Refactor Calibration Frame Controller
tiagohm Oct 8, 2024
49121b0
[api]: Refactor Image Controller
tiagohm Oct 8, 2024
7d77587
[api]: Refactor Flat Wizard Controller
tiagohm Oct 8, 2024
d323584
[api]: Refactor Star Detection Controller
tiagohm Oct 8, 2024
fabefaf
[api]: Refactor Auto Focus Controller
tiagohm Oct 8, 2024
33d56fb
[api]: Refactor Live Stacking Controller
tiagohm Oct 8, 2024
480749d
[api]: Refactor Stacker Controller
tiagohm Oct 8, 2024
dc3caa3
[api]: Refactor Framing Controller
tiagohm Oct 8, 2024
7ea2834
[api]: Refactor INDI Controller
tiagohm Oct 8, 2024
a9b30f7
[api]: Refactor Polar Alignment Controller
tiagohm Oct 8, 2024
957f3ce
[api][desktop]: Refactor Guiding Controller
tiagohm Oct 8, 2024
e9d7493
[api]: Refactor Sequencer Controller
tiagohm Oct 8, 2024
8cf5c4c
[api]: Refactor Sky Atlas Controller
tiagohm Oct 8, 2024
d3e84a6
[api]: Refactor Mount Controller
tiagohm Oct 8, 2024
2cea210
[api]: Refactor Camera Controller
tiagohm Oct 8, 2024
4442459
[api]: Remove Spring Boot
tiagohm Oct 8, 2024
ec1c71c
[api]: Don't use Consumer from rxjava
tiagohm Oct 8, 2024
af87935
[api]: Fix Path serialization
tiagohm Oct 8, 2024
700d087
[desktop]: Implement WebSocket reconnection
tiagohm Oct 8, 2024
20bfed7
[api][desktop]: Fixes
tiagohm Oct 9, 2024
18c114d
[api][desktop]: Fixes & improvements
tiagohm Oct 9, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
run: chmod +x gradlew

- name: Build
run: ./gradlew --no-daemon :api:bootJar
run: ./gradlew --no-daemon :api:shadowJar

- name: Upload Artifact
uses: actions/upload-artifact@v4
Expand Down
12 changes: 3 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
.PHONY: api desktop bootRun build install
.PHONY: api desktop build install

ifeq ($(OS),Windows_NT)
api:
gradlew.bat api:bootJar
gradlew.bat api:shadowJar

desktop:
cd desktop && npm run electron:build

bootRun:
gradlew.bat api:bootRun --args='--server.port=7000'
else
api:
./gradlew api:bootJar
./gradlew api:shadowJar

desktop:
cd desktop && npm run electron:build:deb

bootRun:
./gradlew api:bootRun --args='--server.port=7000'

install:
sudo dpkg -i desktop/release/nebulosa_0.1.0_amd64.deb
endif
Expand Down
2 changes: 1 addition & 1 deletion api/Main.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
value="nebulosa.api.MainKt"/>
<module name="nebulosa.api.main"/>
<option name="PROGRAM_PARAMETERS"
value="--server.port=7000 --spring.jpa.show-sql=true --logging.level.nebulosa=DEBUG"/>
value="--port=7000"/>
<shortenClasspath name="NONE"/>
<method v="2">
<option name="Gradle.BeforeRunTask"
Expand Down
33 changes: 12 additions & 21 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import org.springframework.boot.gradle.tasks.bundling.BootJar
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

plugins {
kotlin("jvm")
id("org.springframework.boot") version "3.3.3"
id("io.spring.dependency-management") version "1.1.6"
kotlin("plugin.spring")
kotlin("kapt")
id("io.objectbox")
id("com.gradleup.shadow")
}

dependencies {
Expand Down Expand Up @@ -38,30 +36,23 @@ dependencies {
implementation(libs.eventbus)
implementation(libs.okhttp)
implementation(libs.oshi)
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-web") {
exclude(module = "spring-boot-starter-tomcat")
}
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-websocket") {
exclude(module = "spring-boot-starter-tomcat")
}
implementation("org.springframework.boot:spring-boot-starter-undertow")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
annotationProcessor("org.springframework:spring-context-indexer:6.1.12")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
implementation(libs.javalin)
implementation(libs.koin)
implementation(libs.airline)

testImplementation(project(":nebulosa-astrobin-api"))
testImplementation(project(":nebulosa-skycatalog-stellarium"))
testImplementation(project(":nebulosa-test"))
}

tasks.withType<BootJar> {
archiveFileName = "api.jar"
destinationDirectory = file("$rootDir/desktop")
tasks.withType<ShadowJar> {
isZip64 = true

archiveFileName.set("api.jar")
destinationDirectory.set(file("../desktop"))

manifest {
attributes["Start-Class"] = "nebulosa.api.MainKt"
attributes["Main-Class"] = "nebulosa.api.MainKt"
}
}

Expand Down
47 changes: 12 additions & 35 deletions api/src/main/kotlin/nebulosa/api/Main.kt
Original file line number Diff line number Diff line change
@@ -1,57 +1,34 @@
package nebulosa.api

import com.github.rvesse.airline.SingleCommand
import com.sun.jna.Platform
import nebulosa.time.SystemClock
import org.springframework.boot.runApplication
import java.nio.file.Path
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.*
import javax.swing.filechooser.FileSystemView
import kotlin.io.path.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteIfExists
import kotlin.io.path.exists
import kotlin.io.path.listDirectoryEntries

const val APP_DIR_KEY = "app.dir"

fun initAppDirectory(): Path {
val appPath = when {
Platform.isLinux() -> Path.of(System.getProperty("user.home"), ".nebulosa")
Platform.isWindows() -> Path.of(FileSystemView.getFileSystemView().defaultDirectory.path, "Nebulosa")
Platform.isLinux() -> Path(System.getProperty("user.home"), ".nebulosa")
Platform.isWindows() -> Path(FileSystemView.getFileSystemView().defaultDirectory.path, "Nebulosa")
else -> throw IllegalStateException("unsupported operating system")
}

appPath.createDirectories()
System.setProperty("app.dir", "$appPath")
return appPath
}

private fun Path.clearLogIfPastDays(days: Long = 7L) {
if (exists()) {
val pastDays = LocalDate.now(SystemClock).minusDays(days)

for (entry in listDirectoryEntries("nebulosa-*.log")) {
val logDate = entry.fileName.toString()
.replace("nebulosa-", "")
.replace(".log", "")
.let { runCatching { LocalDate.parse(it, DateTimeFormatter.ISO_LOCAL_DATE) }.getOrNull() }
?: continue

if (pastDays.isAfter(logDate)) {
entry.deleteIfExists()
}
}
}
.createDirectories()
.also { System.setProperty(APP_DIR_KEY, "$it") }
}

fun main(args: Array<String>) {
with(initAppDirectory()) {
Path.of("$this", "logs").createDirectories().clearLogIfPastDays()
Path.of("$this", "data").createDirectories().also { System.setProperty("DATA_PATH", "$it") }
}
initAppDirectory()

// Sets default locale to en_US.
Locale.setDefault(Locale.ENGLISH)

// Run the Spring Boot application.
runApplication<Nebulosa>(*args)
val parser = SingleCommand.singleCommand(Nebulosa::class.java)
val nebulosa = parser.parse(*args)
nebulosa.run()
}
77 changes: 69 additions & 8 deletions api/src/main/kotlin/nebulosa/api/Nebulosa.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,81 @@
package nebulosa.api

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
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.json.JavalinJackson
import nebulosa.api.atlas.Location
import nebulosa.api.beans.modules.DeviceModule
import nebulosa.api.inject.*
import nebulosa.json.PathModule
import nebulosa.log.loggerFor
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent
import org.springframework.context.event.EventListener
import org.koin.core.context.startKoin
import java.util.concurrent.ConcurrentHashMap

@SpringBootApplication
class Nebulosa {
@Command(name = "nebulosa")
class Nebulosa : Runnable, AutoCloseable {

@EventListener
private fun onServletWebServerInitializedEvent(event: ServletWebServerInitializedEvent) {
LOG.info("server is started at port: ${event.webServer.port}")
@Option(name = ["-h", "--host"])
private var host = "0.0.0.0"

@Option(name = ["-p", "--port"])
private var port = 0

private lateinit var app: Javalin

override fun run() {
// Run the server.
app = Javalin.create { config ->
config.showJavalinBanner = false
// JACKSON
config.jsonMapper(JavalinJackson(OBJECT_MAPPER))
// CORS
config.bundledPlugins.enableCors { cors ->
cors.addRule {
it.anyHost()
it.exposeHeader("X-Image-Info")
}
}
}.start(host, port)

koinApp.modules(appModule(app))
koinApp.modules(objectMapperModule(OBJECT_MAPPER))
koinApp.modules(servicesModule())
koinApp.modules(controllersModule())
startKoin(koinApp)

LOG.info("server is started at port: {}", app.port())
}

override fun close() {
app.stop()
}

private data object LocationConverter : (String) -> Location? {

private val CACHED_LOCATION = ConcurrentHashMap<String, Location>(4)

override fun invoke(value: String): Location? {
return if (value.isBlank()) null
else CACHED_LOCATION.computeIfAbsent(value) { OBJECT_MAPPER.readValue(value, Location::class.java) }
}
}

companion object {

@JvmStatic private val LOG = loggerFor<Nebulosa>()

@JvmStatic private val OBJECT_MAPPER = jsonMapper {
addModule(JavaTimeModule())
addModule(PathModule())
addModule(DeviceModule())
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,59 +1,72 @@
package nebulosa.api.alignment.polar

import nebulosa.api.alignment.polar.darv.DARVEvent
import io.javalin.Javalin
import io.javalin.http.Context
import io.javalin.http.bodyAsClass
import nebulosa.api.alignment.polar.darv.DARVStartRequest
import nebulosa.api.alignment.polar.tppa.TPPAEvent
import nebulosa.api.alignment.polar.tppa.TPPAStartRequest
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guider.GuideOutput
import nebulosa.indi.device.mount.Mount
import org.springframework.web.bind.annotation.*
import nebulosa.api.connection.ConnectionService
import nebulosa.api.javalin.notNull
import nebulosa.api.javalin.valid

@RestController
@RequestMapping("polar-alignment")
class PolarAlignmentController(
app: Javalin,
private val polarAlignmentService: PolarAlignmentService,
private val connectionService: ConnectionService,
) {

@PutMapping("darv/{camera}/{guideOutput}/start")
fun darvStart(
camera: Camera, guideOutput: GuideOutput,
@RequestBody body: DARVStartRequest,
) = polarAlignmentService.darvStart(camera, guideOutput, body)
init {
app.put("polar-alignment/darv/{camera}/{guideOutput}/start", ::darvStart)
app.put("polar-alignment/darv/{camera}/stop", ::darvStop)
app.get("polar-alignment/darv/{camera}/status", ::darvStatus)
app.put("polar-alignment/tppa/{camera}/{mount}/start", ::tppaStart)
app.put("polar-alignment/tppa/{camera}/stop", ::tppaStop)
app.put("polar-alignment/tppa/{camera}/pause", ::tppaPause)
app.put("polar-alignment/tppa/{camera}/unpause", ::tppaUnpause)
app.get("polar-alignment/tppa/{camera}/status", ::tppaStatus)
}

private fun darvStart(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")).notNull()
val guideOutput = connectionService.guideOutput(ctx.pathParam("guideOutput")).notNull()
val body = ctx.bodyAsClass<DARVStartRequest>().valid()
polarAlignmentService.darvStart(camera, guideOutput, body)
}

@PutMapping("darv/{camera}/stop")
fun darvStop(camera: Camera) {
private fun darvStop(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")) ?: return
polarAlignmentService.darvStop(camera)
}

@GetMapping("darv/{camera}/status")
fun darvStatus(camera: Camera): DARVEvent? {
return polarAlignmentService.darvStatus(camera)
private fun darvStatus(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")).notNull()
polarAlignmentService.darvStatus(camera)?.also(ctx::json)
}

@PutMapping("tppa/{camera}/{mount}/start")
fun tppaStart(
camera: Camera, mount: Mount,
@RequestBody body: TPPAStartRequest,
) = polarAlignmentService.tppaStart(camera, mount, body)
private fun tppaStart(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")).notNull()
val mount = connectionService.mount(ctx.pathParam("mount")).notNull()
val body = ctx.bodyAsClass<TPPAStartRequest>().valid()
polarAlignmentService.tppaStart(camera, mount, body)
}

@PutMapping("tppa/{camera}/stop")
fun tppaStop(camera: Camera) {
private fun tppaStop(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")) ?: return
polarAlignmentService.tppaStop(camera)
}

@PutMapping("tppa/{camera}/pause")
fun tppaPause(camera: Camera) {
private fun tppaPause(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")) ?: return
polarAlignmentService.tppaPause(camera)
}

@PutMapping("tppa/{camera}/unpause")
fun tppaUnpause(camera: Camera) {
private fun tppaUnpause(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")) ?: return
polarAlignmentService.tppaUnpause(camera)
}

@GetMapping("tppa/{camera}/status")
fun tppaStatus(camera: Camera): TPPAEvent? {
return polarAlignmentService.tppaStatus(camera)
private fun tppaStatus(ctx: Context) {
val camera = connectionService.camera(ctx.pathParam("camera")).notNull()
polarAlignmentService.tppaStatus(camera)?.also(ctx::json)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import nebulosa.api.alignment.polar.tppa.TPPAStartRequest
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guider.GuideOutput
import nebulosa.indi.device.mount.Mount
import org.springframework.stereotype.Service

@Service
class PolarAlignmentService(
private val darvExecutor: DARVExecutor,
private val tppaExecutor: TPPAExecutor,
Expand Down
Loading