Files
SHiNE-server/build.gradle

340 lines
12 KiB
Groovy

plugins {
id 'java'
id 'application'
id 'com.github.johnrengelman.shadow' version '8.1.1'
}
def appVersionProps = new Properties()
def appVersionFile = file('VERSION.properties')
if (appVersionFile.exists()) {
appVersionFile.withInputStream { appVersionProps.load(it) }
}
def serverVersionFromFile = String.valueOf(appVersionProps.getProperty('server.version', '1.1_codex')).trim()
allprojects {
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
}
group = 'shine'
version = serverVersionFromFile
layout.buildDirectory.set(file('SHiNE-server/build'))
sourceSets {
main {
java.srcDirs = ['SHiNE-server/src/main/java']
resources.srcDirs = ['SHiNE-server/src/main/resources']
}
test {
java.srcDirs = ['SHiNE-server/src/test/java']
resources.srcDirs = ['SHiNE-server/src/test/resources']
}
}
tasks.jar {
enabled = false // это что бы не создавала обычный джар, а будет только толстый джар
}
tasks.processResources {
filteringCharset = 'UTF-8'
filesMatching('application.properties') {
expand(projectVersion: project.version.toString())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.eclipse.jetty:jetty-server:11.0.20' // WS сервер
implementation 'org.eclipse.jetty:jetty-servlet:11.0.20'
implementation 'org.eclipse.jetty.websocket:websocket-jetty-server:11.0.20'
implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' // шифрование
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' // json
// implementation 'org.slf4j:slf4j-api:2.0.9'
implementation 'ch.qos.logback:logback-classic:1.5.6'
// Logback (реализация SLF4J + классический модуль)
runtimeOnly "ch.qos.logback:logback-classic:1.5.6"
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation "org.slf4j:slf4j-api:2.0.16" // вызов логгера
// runtimeOnly "org.apache.logging.log4j:log4j-core:2.24.3" // Реализация: Log4j2 пишет в файл/консоль
// runtimeOnly "org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3" // Реализация: Log4j2 пишет в файл/консоль
implementation project(':shine-server-config') // модуль настроек из application.properties
implementation project(":shine-server-log") // модуль логирования и уведомления админов
implementation project(':shine-server-crypto') // модуль сервера для работы с криптографией
implementation project(':shine-server-db') // модуль для работы с БД содержит и сущности из БД и саму работу с БД
implementation project(':shine-server-blockchain') // модуль для работы с блокчейном
implementation project(':shine-server-geo') // модуль для определения геолокации по IP
implementation project(':shine-server-net-protocol') // Модуль отвечающий за протокол (классы Net..Request/Response
implementation project(':shine-server-net-server') // Хэндлеры для обработки сетевых запросов
// -------------------- ТЕСТЫ (JUnit 5) --------------------
// Один BOM на всё семейство JUnit (Jupiter + Platform модули)
testImplementation platform("org.junit:junit-bom:5.10.2")
// JUnit Jupiter (Test, BeforeAll, Assertions)
testImplementation "org.junit.jupiter:junit-jupiter"
// JUnit Platform Suite (@Suite, @SelectClasses)
testImplementation "org.junit.platform:junit-platform-suite-api"
testRuntimeOnly "org.junit.platform:junit-platform-suite-engine"
// Нужно для компиляции RussianSummaryListener (org.junit.platform.launcher.*)
// и чтобы JUnit мог подхватить listener при запуске
testImplementation "org.junit.platform:junit-platform-launcher"
testRuntimeOnly "org.junit.platform:junit-platform-launcher"
}
test {
useJUnitPlatform()
}
application {
// 👇 класс с методом main
mainClass = 'server.ws.WsServer'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
shadowJar {
// создаём 1 файл без постфиксов
archiveBaseName.set('shine-server')
archiveClassifier.set('')
archiveVersion.set('')
mergeServiceFiles()
manifest {
attributes(
'Main-Class': 'server.ws.WsServer'
)
}
}
tasks.named('test') {
enabled = false
}
tasks.register('cleanServerLogs') {
group = "!!test"
description = "Clear server logs/app.log and remove rolled log files"
doLast {
File logsDir = file('SHiNE-server/logs')
if (!logsDir.exists()) {
logsDir.mkdirs()
}
File appLog = new File(logsDir, 'app.log')
if (!appLog.exists()) {
appLog.createNewFile()
}
appLog.text = ''
fileTree(logsDir) {
include 'app.*.log'
}.files.each { File f ->
if (!f.delete()) {
throw new GradleException("Failed to delete log file: ${f.absolutePath}")
}
}
println "Server logs cleared: ${logsDir.absolutePath}"
}
}
tasks.register('integrationTest', JavaExec) {
group = "!!test"
description = "Clean data → kill 7070 → start WS → run all IT tests"
classpath = sourceSets.test.runtimeClasspath
mainClass = "test.it.IT_RunAllCleanStartWsMain"
workingDir = file('SHiNE-server')
// пробрасываем системные флаги (по желанию)
systemProperty "it.debug", System.getProperty("it.debug", "true")
systemProperty "it.login", System.getProperty("it.login", "anya24")
dependsOn testClasses
}
tasks.named('build') {
finalizedBy tasks.named('integrationTest')
}
tasks.register('deployServerProduction', JavaExec) {
group = "!!deployment"
description = "Production deploy: build → upload to shineup.me → restart service (только после явного подтверждения)"
classpath = sourceSets.test.runtimeClasspath
mainClass = "test.it.IT_DeployRestartNoCleanNoTestsMain"
workingDir = file('SHiNE-server')
dependsOn shadowJar
systemProperty "it.remoteHost", System.getProperty("it.remoteHost", "shineup.me")
systemProperty "it.remoteUser", System.getProperty("it.remoteUser", "player")
systemProperty "it.remoteDir", System.getProperty("it.remoteDir", "/home/player/SHiNE/shine-server")
systemProperty "it.service", System.getProperty("it.service", "shine-server")
systemProperty "it.localJar", System.getProperty("it.localJar", "build/libs/shine-server.jar")
dependsOn testClasses
}
tasks.register('deployUIProduction', Exec) {
group = "!!deployment"
description = "Production UI deploy: shineup.me (только после явного подтверждения)"
workingDir = rootDir
commandLine 'bash', file('deploy_shine-PWA.sh').absolutePath
}
tasks.register('deployServer', Exec) {
group = "!!deployment"
description = "Default deploy server: test2.shineup.me"
dependsOn shadowJar
workingDir = rootDir
environment 'LOCAL_JAR', file('SHiNE-server/build/libs/shine-server.jar').absolutePath
commandLine 'bash', file('deploy_shine-server_test2.sh').absolutePath
}
tasks.register('deployUI', Exec) {
group = "!!deployment"
description = "Default deploy UI: test2.shineup.me"
workingDir = rootDir
commandLine 'bash', file('deploy_shine-ui_test2.sh').absolutePath
}
tasks.register('deployServerTest2') {
group = "!!deployment"
description = "Явный алиас основного test deploy server: test2.shineup.me"
dependsOn tasks.named('deployServer')
}
tasks.register('deployUITest2') {
group = "!!deployment"
description = "Явный алиас основного test deploy UI: test2.shineup.me"
dependsOn tasks.named('deployUI')
}
tasks.register('deployServerTest', Exec) {
group = "!!deployment"
description = "Резервный test deploy: test.shineup.me (пока не использовать)"
dependsOn shadowJar
workingDir = rootDir
environment 'LOCAL_JAR', file('SHiNE-server/build/libs/shine-server.jar').absolutePath
commandLine 'bash', file('deploy_shine-server_test.sh').absolutePath
}
tasks.register('deployUITest', Exec) {
group = "!!deployment"
description = "Резервный test UI deploy: test.shineup.me (пока не использовать)"
workingDir = rootDir
commandLine 'bash', file('deploy_shine-ui_test.sh').absolutePath
}
tasks.register('startLocal', Exec) {
group = "!!run"
description = "Builds server, starts local WS server and local HTTP UI for end-to-end local testing"
dependsOn shadowJar
dependsOn cleanServerLogs
workingDir = rootDir
def wsPort = System.getProperty("localWsPort", "7070")
def webPort = System.getProperty("localWebPort", "8088")
commandLine 'bash', '-lc', """
set -euo pipefail
JAR_PATH="${file('SHiNE-server/build/libs/shine-server.jar').absolutePath}"
UI_DIR="${file('shine-UI').absolutePath}"
WS_PORT="${wsPort}"
WEB_PORT="${webPort}"
is_port_busy() {
local port="\$1"
if command -v ss >/dev/null 2>&1; then
ss -ltnH "sport = :\$port" | grep -q .
elif command -v lsof >/dev/null 2>&1; then
lsof -iTCP:"\$port" -sTCP:LISTEN >/dev/null 2>&1
else
return 1
fi
}
pick_free_port() {
local p="\$1"
while is_port_busy "\$p"; do
p=\$((p + 1))
done
echo "\$p"
}
WS_PORT="\$(pick_free_port "\$WS_PORT")"
WEB_PORT="\$(pick_free_port "\$WEB_PORT")"
echo "Starting SHiNE local stack..."
echo "WS server port: \$WS_PORT"
echo "UI HTTP port: \$WEB_PORT"
echo "Client URL: http://localhost:\$WEB_PORT/?localWsPort=\$WS_PORT"
(
cd "${file('SHiNE-server').absolutePath}"
java -Dserver.port="\$WS_PORT" -jar "\$JAR_PATH"
) &
SERVER_PID=\$!
trap 'kill \$SERVER_PID 2>/dev/null || true' EXIT INT TERM
CLIENT_URL="http://localhost:\$WEB_PORT/?localWsPort=\$WS_PORT"
if command -v xdg-open >/dev/null 2>&1; then
(xdg-open "\$CLIENT_URL" >/dev/null 2>&1 || true) &
elif command -v open >/dev/null 2>&1; then
(open "\$CLIENT_URL" >/dev/null 2>&1 || true) &
elif command -v cmd.exe >/dev/null 2>&1; then
(cmd.exe /c start "" "\$CLIENT_URL" >/dev/null 2>&1 || true) &
else
echo "Browser auto-open is not available on this host. Open manually: \$CLIENT_URL"
fi
SPA_SERVER_SCRIPT="${file('scripts/local_spa_server.py').absolutePath}"
if command -v python3 >/dev/null 2>&1; then
SHINE_UI_PORT="\$WEB_PORT" python3 "\$SPA_SERVER_SCRIPT"
else
SHINE_UI_PORT="\$WEB_PORT" python "\$SPA_SERVER_SCRIPT"
fi
"""
}
tasks.register('startLocalWithBuild') {
group = "!!run"
description = "Build server (build) and then start local stack (startLocal)"
dependsOn tasks.named('build')
dependsOn tasks.named('startLocal')
}
tasks.named('startLocal').configure {
mustRunAfter tasks.named('build')
}