Application mutex

This commit is contained in:
Aria Moradi 2021-05-19 16:36:17 +04:30
parent 29dea10be2
commit 02802fab97
7 changed files with 99 additions and 9 deletions

View File

@ -12,7 +12,9 @@ plugins {
}
repositories {
mavenCentral()
maven {
url = uri("https://repo1.maven.org/maven2/")
}
maven {
url = uri("https://jitpack.io")
}
@ -53,7 +55,9 @@ dependencies {
// api
implementation("io.javalin:javalin:3.13.6")
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.3")
// jackson version is tied to javalin, ref: `io.javalin.core.util.OptionalDependency`
implementation("com.fasterxml.jackson.core:jackson-databind:2.10.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.10.3")
// Exposed ORM
val exposedVersion = "0.31.1"

View File

@ -33,7 +33,7 @@ import ir.armor.tachidesk.impl.Source.getSourceList
import ir.armor.tachidesk.impl.backup.BackupFlags
import ir.armor.tachidesk.impl.backup.legacy.LegacyBackupExport.createLegacyBackup
import ir.armor.tachidesk.impl.backup.legacy.LegacyBackupImport.restoreLegacyBackup
import ir.armor.tachidesk.server.internal.About.getAbout
import ir.armor.tachidesk.server.impl_internal.About.getAbout
import ir.armor.tachidesk.server.util.openInBrowser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@ -10,6 +10,7 @@ package ir.armor.tachidesk.server
import ch.qos.logback.classic.Level
import eu.kanade.tachiyomi.App
import ir.armor.tachidesk.model.database.databaseUp
import ir.armor.tachidesk.server.util.AppMutex.handleAppMutex
import ir.armor.tachidesk.server.util.systemTray
import mu.KotlinLogging
import org.kodein.di.DI
@ -36,7 +37,7 @@ class ApplicationDirs(
val serverConfig: ServerConfig by lazy { GlobalConfigManager.module() }
val systemTray by lazy { systemTray() }
val systemTrayInstance by lazy { systemTray() }
val androidCompat by lazy { AndroidCompat() }
@ -66,6 +67,8 @@ fun applicationSetup() {
ServerConfig.register(GlobalConfigManager.config)
)
handleAppMutex()
// Load config API
DI.global.addImport(ConfigKodeinModule().create())
// Load Android compatibility dependencies
@ -97,7 +100,7 @@ fun applicationSetup() {
// create system tray
if (serverConfig.systemTrayEnabled) {
try {
systemTray
systemTrayInstance
} catch (e: Throwable) { // cover both java.lang.Exception and java.lang.Error
e.printStackTrace()
}

View File

@ -1,4 +1,4 @@
package ir.armor.tachidesk.server.internal
package ir.armor.tachidesk.server.impl_internal
/*
* Copyright (C) Contributors to the Suwayomi project

View File

@ -0,0 +1,13 @@
package ir.armor.tachidesk.server.util
import kotlin.system.exitProcess
enum class ExitCode(val code: Int) {
Success(0),
MutexCheckFailedTachideskRunning(1),
MutexCheckFailedAnotherAppRunning(2);
}
fun shutdownApp(exitCode: ExitCode) {
exitProcess(exitCode.code)
}

View File

@ -0,0 +1,71 @@
package ir.armor.tachidesk.server.util
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import io.javalin.plugin.json.JavalinJackson
import ir.armor.tachidesk.server.impl_internal.AboutDataClass
import ir.armor.tachidesk.server.serverConfig
import ir.armor.tachidesk.server.util.AppMutex.AppMutexStat.Clear
import ir.armor.tachidesk.server.util.AppMutex.AppMutexStat.OtherApplicationRunning
import ir.armor.tachidesk.server.util.AppMutex.AppMutexStat.TachideskInstanceRunning
import mu.KotlinLogging
import okhttp3.OkHttpClient
import okhttp3.Request.Builder
import java.io.IOException
import java.util.concurrent.TimeUnit
object AppMutex {
private val logger = KotlinLogging.logger {}
private enum class AppMutexStat(val stat: Int) {
Clear(0),
TachideskInstanceRunning(1),
OtherApplicationRunning(2)
}
private val appIP = if (serverConfig.ip == "0.0.0.0") "127.0.0.1" else serverConfig.ip
private fun checkAppMutex(): AppMutexStat {
val client = OkHttpClient.Builder()
.connectTimeout(200, TimeUnit.MILLISECONDS)
.build()
val request = Builder()
.url("http://$appIP:${serverConfig.port}/api/v1/about/")
.build()
val response = try {
client.newCall(request).execute().use { response -> response.body!!.string() }
} catch (e: IOException) {
return AppMutexStat.Clear
}
return try {
JavalinJackson.fromJson(response, AboutDataClass::class.java)
AppMutexStat.TachideskInstanceRunning
} catch (e: IOException) {
AppMutexStat.OtherApplicationRunning
}
}
fun handleAppMutex() {
when (checkAppMutex()) {
Clear -> {
logger.info("Mutex status is clear, Resuming startup.")
}
TachideskInstanceRunning -> {
logger.info("Another instance of Tachidesk is running on $appIP:${serverConfig.port}, Aborting.")
shutdownApp(ExitCode.MutexCheckFailedTachideskRunning)
}
OtherApplicationRunning -> {
logger.error("A non Tachidesk application is running on $appIP:${serverConfig.port}, Aborting.")
shutdownApp(ExitCode.MutexCheckFailedAnotherAppRunning)
}
}
}
}

View File

@ -15,7 +15,7 @@ import dorkbox.util.Desktop
import ir.armor.tachidesk.server.BuildConfig
import ir.armor.tachidesk.server.ServerConfig
import ir.armor.tachidesk.server.serverConfig
import kotlin.system.exitProcess
import ir.armor.tachidesk.server.util.ExitCode.Success
fun openInBrowser() {
try {
@ -53,8 +53,7 @@ fun systemTray(): SystemTray? {
mainMenu.add(
MenuItem("Quit") {
systemTray.shutdown()
exitProcess(0)
shutdownApp(Success)
}
)