Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit 4622569

Browse files
committed
feat(punishment): implement service for managing player punishments with enhanced operations
1 parent 77a9da8 commit 4622569

File tree

26 files changed

+812
-282
lines changed

26 files changed

+812
-282
lines changed

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ buildscript {
1313

1414
plugins {
1515
id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.17.0"
16-
id("io.freefair.aspectj.post-compile-weaving") version "8.13.1"
16+
// id("io.freefair.aspectj.post-compile-weaving") version "8.13.1"
1717
java
1818
}
1919

@@ -30,7 +30,7 @@ allprojects {
3030
}
3131

3232
apply(plugin = "java")
33-
apply(plugin = "io.freefair.aspectj.post-compile-weaving")
33+
// apply(plugin = "io.freefair.aspectj.post-compile-weaving")
3434

3535
dependencies {
3636
// implementation(platform("org.springframework.boot:spring-boot-dependencies:3.4.4"))

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/SurfCloudApplication.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ package dev.slne.surf.cloud.api.common
33
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter
44
import org.springframework.boot.autoconfigure.AutoConfigurationPackage
55
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
6-
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
76
import org.springframework.boot.autoconfigure.domain.EntityScan
87
import org.springframework.boot.context.TypeExcludeFilter
98
import org.springframework.cache.annotation.EnableCaching
9+
import org.springframework.context.annotation.AdviceMode
1010
import org.springframework.context.annotation.ComponentScan
11-
import org.springframework.context.annotation.EnableAspectJAutoProxy
1211
import org.springframework.context.annotation.FilterType
1312
import org.springframework.scheduling.annotation.EnableAsync
1413
import org.springframework.scheduling.annotation.EnableScheduling
@@ -24,10 +23,10 @@ import java.lang.annotation.Inherited
2423
@Target(AnnotationTarget.CLASS)
2524
@Retention(AnnotationRetention.RUNTIME)
2625
@EnableScheduling
27-
@EnableAsync
28-
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
26+
@EnableAsync(mode = AdviceMode.ASPECTJ)
27+
//@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
2928
@EntityScan
30-
@EnableCaching
29+
@EnableCaching(mode = AdviceMode.ASPECTJ)
3130
@AutoConfigurationPackage
3231
@Inherited
3332
@EnableAutoConfiguration

surf-cloud-api/surf-cloud-api-server/src/main/kotlin/dev/slne/surf/cloud/api/server/exposed/service/AbstractExposedDAOService.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import kotlinx.coroutines.CoroutineScope
88
import kotlinx.coroutines.Dispatchers
99
import kotlinx.coroutines.SupervisorJob
1010
import org.jetbrains.exposed.dao.Entity
11+
import org.springframework.beans.factory.annotation.Autowired
12+
import org.springframework.context.ApplicationContext
1113
import kotlin.coroutines.CoroutineContext
1214

1315
/**
@@ -23,6 +25,11 @@ abstract class AbstractExposedDAOService<K, V : Entity<*>>(
2325
cacheCustomizer: Caffeine<Any, Any>.() -> Unit = {},
2426
private val context: CoroutineContext = Dispatchers.IO
2527
) {
28+
@Autowired
29+
lateinit var applicationContext: ApplicationContext
30+
31+
protected val self get() = applicationContext.getBean(javaClass)
32+
2633
/**
2734
* Cache for storing loaded entities, using Caffeine with coroutine-based loading.
2835
*/
@@ -34,7 +41,7 @@ abstract class AbstractExposedDAOService<K, V : Entity<*>>(
3441
val cacheContext = context + cacheName + SupervisorJob()
3542

3643
asLoadingCache<K, V?>(CoroutineScope(cacheContext)) {
37-
load(it)
44+
self.load(it)
3845
}
3946
}
4047

@@ -74,7 +81,7 @@ abstract class AbstractExposedDAOService<K, V : Entity<*>>(
7481
createIfMissing: Boolean = true,
7582
block: suspend V.() -> Unit
7683
) {
77-
val entity = cache.get(key) ?: if (createIfMissing) create(key) else null
84+
val entity = cache.get(key) ?: if (createIfMissing) self.create(key) else null
7885
if (entity != null) {
7986
entity.block()
8087
cache.put(key, entity)

surf-cloud-api/surf-cloud-api-server/src/main/kotlin/dev/slne/surf/cloud/api/server/plugin/AdditionalStandaloneConfiguration.kt

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,45 @@
11
package dev.slne.surf.cloud.api.server.plugin
22

33
import dev.slne.surf.cloud.api.server.plugin.utils.PluginUtilProxies
4+
import dev.slne.surf.surfapi.core.api.util.logger
45
import kotlinx.coroutines.CoroutineScope
56
import kotlinx.coroutines.launch
67
import kotlinx.coroutines.reactive.awaitFirstOrNull
78
import kotlinx.coroutines.suspendCancellableCoroutine
9+
import org.aopalliance.aop.Advice
810
import org.aspectj.lang.ProceedingJoinPoint
911
import org.aspectj.lang.annotation.Around
1012
import org.aspectj.lang.annotation.Aspect
1113
import org.aspectj.lang.reflect.MethodSignature
1214
import org.jetbrains.exposed.spring.SpringTransactionManager
1315
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
1416
import org.reactivestreams.Publisher
17+
import org.springframework.aop.aspectj.AspectJExpressionPointcut
18+
import org.springframework.aop.support.DefaultPointcutAdvisor
1519
import org.springframework.beans.factory.getBean
20+
import org.springframework.boot.autoconfigure.AutoConfigurationPackages
1621
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
1722
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
1823
import org.springframework.cache.annotation.EnableCaching
1924
import org.springframework.context.ApplicationContext
20-
import org.springframework.context.annotation.AdviceMode
21-
import org.springframework.context.annotation.Configuration
22-
import org.springframework.context.annotation.Import
25+
import org.springframework.context.ApplicationContextAware
26+
import org.springframework.context.ConfigurableApplicationContext
27+
import org.springframework.context.annotation.*
2328
import org.springframework.core.KotlinDetector
2429
import org.springframework.core.Ordered
30+
import org.springframework.core.PriorityOrdered
2531
import org.springframework.core.annotation.AnnotatedElementUtils
2632
import org.springframework.core.annotation.Order
33+
import org.springframework.instrument.classloading.LoadTimeWeaver
34+
import org.springframework.instrument.classloading.SimpleThrowawayClassLoader
2735
import org.springframework.scheduling.annotation.EnableAsync
2836
import org.springframework.stereotype.Component
2937
import org.springframework.transaction.annotation.EnableTransactionManagement
38+
import java.lang.instrument.ClassFileTransformer
39+
import java.lang.instrument.Instrumentation
3040
import java.lang.reflect.Method
41+
import java.security.ProtectionDomain
42+
import java.util.concurrent.CopyOnWriteArrayList
3143
import kotlin.coroutines.Continuation
3244
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
3345
import kotlin.coroutines.resume
@@ -37,7 +49,11 @@ import kotlin.coroutines.startCoroutine
3749
@Target(AnnotationTarget.CLASS)
3850
@Retention(AnnotationRetention.RUNTIME)
3951
@Configuration
40-
@Import(CoroutineTransactionalAspect::class)
52+
@Import(
53+
CoroutineTransactionalAspect::class,
54+
LoadTimeWeavingConfiguration::class,
55+
TransactionConfiguration::class
56+
)
4157
@EnableAsync(mode = AdviceMode.ASPECTJ)
4258
@EnableCaching(mode = AdviceMode.ASPECTJ)
4359
@EnableAutoConfiguration(
@@ -52,6 +68,95 @@ annotation class AdditionalStandaloneConfiguration
5268
@Configuration
5369
class TransactionConfiguration
5470

71+
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
72+
@Configuration
73+
class LoadTimeWeavingConfiguration(context: ApplicationContext) : LoadTimeWeavingConfigurer {
74+
private val allowedPrefixes = AutoConfigurationPackages.get(context)
75+
.map { it.trimEnd('.') + "." }
76+
// .plus(listOf("org.springframework."))
77+
78+
val weaver = LoadTimeWeaverImpl(
79+
LoadTimeWeaverImpl.getInstrumentation(),
80+
context.classLoader ?: error("Application context does not have a class loader"),
81+
allowedPrefixes
82+
)
83+
84+
override fun getLoadTimeWeaver(): LoadTimeWeaver = weaver
85+
86+
class LoadTimeWeaverImpl(
87+
private val instrumentation: Instrumentation,
88+
private val classLoader: ClassLoader,
89+
private val allowedPrefixes: List<String>
90+
) : LoadTimeWeaver {
91+
private val transformers = CopyOnWriteArrayList<ClassFileTransformer>()
92+
93+
override fun addTransformer(transformer: ClassFileTransformer) {
94+
val actualTransformer =
95+
FilteringClassFileTransformer(transformer, classLoader, allowedPrefixes)
96+
if (transformers.addIfAbsent(actualTransformer)) {
97+
instrumentation.addTransformer(actualTransformer)
98+
}
99+
}
100+
101+
override fun getInstrumentableClassLoader(): ClassLoader = classLoader
102+
override fun getThrowawayClassLoader(): ClassLoader =
103+
SimpleThrowawayClassLoader(classLoader)
104+
105+
class FilteringClassFileTransformer(
106+
private val targetTransformer: ClassFileTransformer,
107+
private val targetClassLoader: ClassLoader,
108+
private val allowedPrefixes: List<String>
109+
) : ClassFileTransformer {
110+
override fun transform(
111+
loader: ClassLoader?,
112+
className: String?,
113+
classBeingRedefined: Class<*>?,
114+
protectionDomain: ProtectionDomain?,
115+
classfileBuffer: ByteArray?
116+
): ByteArray? {
117+
if (loader != targetClassLoader || className == null) return null
118+
val dotted = className.replace('/', '.')
119+
if (allowedPrefixes.none { dotted.startsWith(it) }) {
120+
return null
121+
}
122+
123+
return try {
124+
targetTransformer.transform(
125+
loader,
126+
className,
127+
classBeingRedefined,
128+
protectionDomain,
129+
classfileBuffer
130+
)
131+
} catch (ex: Throwable) {
132+
log.atWarning()
133+
.withCause(ex)
134+
.log("LTW: skipping weaving for $dotted due to ${ex.javaClass.simpleName}: ${ex.message}")
135+
null
136+
}
137+
}
138+
}
139+
140+
companion object {
141+
private val log = logger()
142+
private const val AGENT_CLASS =
143+
"org.springframework.instrument.InstrumentationSavingAgent"
144+
private val agentClass: Class<*> by lazy {
145+
Class.forName(AGENT_CLASS, true, javaClass.classLoader.parent)
146+
}
147+
private val agentMethod by lazy {
148+
agentClass.getDeclaredMethod(
149+
"getInstrumentation",
150+
)
151+
}
152+
153+
fun getInstrumentation(): Instrumentation {
154+
return agentMethod.invoke(null) as Instrumentation
155+
}
156+
}
157+
158+
}
159+
}
55160

56161
/**
57162
* **Internal** Aspect that wraps every *suspending* call annotated (directly or
@@ -90,8 +195,13 @@ class TransactionConfiguration
90195
*/
91196
@Aspect
92197
@Component
93-
@Order(Ordered.LOWEST_PRECEDENCE)
94-
class CoroutineTransactionalAspect(private val context: ApplicationContext) {
198+
class CoroutineTransactionalAspect(private val context: ApplicationContext) : Advice, PriorityOrdered {
199+
200+
init {
201+
repeat(20) {
202+
println("CoroutineTransactionalAspect initialized with context: $context")
203+
}
204+
}
95205

96206
/**
97207
* Around-advice for any method or class annotated with
@@ -182,4 +292,7 @@ class CoroutineTransactionalAspect(private val context: ApplicationContext) {
182292
)
183293
}
184294

295+
override fun getOrder(): Int {
296+
return Ordered.LOWEST_PRECEDENCE
297+
}
185298
}

surf-cloud-api/surf-cloud-api-server/src/main/kotlin/dev/slne/surf/cloud/api/server/plugin/CoroutineTransactional.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.slne.surf.cloud.api.server.plugin
22

3+
import kotlinx.coroutines.CoroutineScope
34
import org.springframework.aot.hint.annotation.Reflective
45
import java.lang.annotation.Inherited
56
import kotlin.annotation.AnnotationRetention.RUNTIME
@@ -59,4 +60,13 @@ annotation class CoroutineTransactional(
5960
FALSE(false),
6061
DEFAULT(null);
6162
}
63+
64+
interface ScopeProvider {
65+
/**
66+
* Provides the current coroutine scope for the transaction.
67+
* This is used to ensure that the transaction is suspended correctly
68+
* when the coroutine yields.
69+
*/
70+
fun getCurrentScope(): CoroutineScope
71+
}
6272
}

surf-cloud-api/surf-cloud-api-server/src/main/kotlin/dev/slne/surf/cloud/api/server/plugin/utils/plugin-utils.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,29 @@ val currentDb
1212
getCallerClass()?.classLoader as? SpringPluginClassloader
1313
?: error("Not in plugin classloader!")
1414
)
15+
16+
fun pluginContext(classloader: SpringPluginClassloader) = classloader.context
17+
val context
18+
get() = pluginContext(
19+
getCallerClass()?.classLoader as? SpringPluginClassloader
20+
?: error("Not in plugin classloader!")
21+
)
22+
23+
val currentContext
24+
get() = pluginContext(
25+
getCallerClass()?.classLoader as? SpringPluginClassloader
26+
?: error("Not in plugin classloader!")
27+
)
28+
29+
fun <T> bean(clazz: Class<T>, classloader: SpringPluginClassloader): T {
30+
return classloader.context.getBean(clazz)
31+
}
32+
33+
fun <T> bean(clazz: Class<T>): T {
34+
return bean(clazz, getCallerClass()?.classLoader as? SpringPluginClassloader
35+
?: error("Not in plugin classloader!"))
36+
}
37+
38+
inline fun <reified T> bean(): T {
39+
return bean(T::class.java)
40+
}

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/messages/MessageManager.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object MessageManager { // TODO: Add more messages
3737
this,
3838
"BEIM VERBINDUNGSAUFBAU IST EIN FEHLER AUFGETRETEN",
3939
{
40-
error("Beim versuch eine Verbindung aufzubauen ist")
40+
error("Beim Versuch, eine Verbindung aufzubauen, ist")
4141
appendNewline()
4242
error("ein unbekannter Fehler aufgetreten.")
4343
},
@@ -48,9 +48,9 @@ object MessageManager { // TODO: Add more messages
4848
val loginTimedOut = buildText {
4949
CommonComponents.renderDisconnectMessage(
5050
this,
51-
"VERBINDUNG ZUR SERVER-INSTANCE WURDE GETRENNT",
51+
"VERBINDUNG ZUR SERVER-INSTANZ WURDE GETRENNT",
5252
{
53-
error("Die Verbindung zur Server-Instance wurde")
53+
error("Die Verbindung zur Server-Instanz wurde")
5454
appendNewline()
5555
error("unerwartet getrennt.")
5656
},
@@ -138,7 +138,7 @@ object MessageManager { // TODO: Add more messages
138138
appendNewline(3)
139139

140140
if (!punishment.securityBan) {
141-
spacer("Du denkst dies ist eine Fehlentscheidung?")
141+
spacer("Du denkst, dies ist eine Fehlentscheidung?")
142142
}
143143
appendNewline {
144144
spacer("Kontaktiere den Support in unserem Discord")
@@ -199,7 +199,7 @@ object MessageManager { // TODO: Add more messages
199199
}
200200

201201
object Mute {
202-
val voiceMutedActionbar = buildText { error("Du bist vom Voicechat ausgeschlossen!") }
202+
val voiceMutedActionbar = buildText { error("Du bist vom Voice-Chat ausgeschlossen!") }
203203

204204
operator fun invoke(punishment: PunishmentMute) = MuteComponentBuilder(punishment)
205205

surf-cloud-core/surf-cloud-core-common/src/main/resources/application.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ spring.jpa.properties.hibernate.cache.use_query_cache=true
1313
spring.jpa.properties.hibernate.cache.region.factory_class=jcache
1414
spring.jpa.properties.hibernate.javax.cache.provider=org.ehcache.jsr107.EhcacheCachingProvider
1515
spring.jpa.properties.hibernate.javax.cache.missing_cache_strategy=create
16+
17+
spring.aop.proxy-target-class=false

surf-cloud-standalone-launcher/src/main/java/dev/slne/surf/cloud/launcher/LauncherAgent.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.jar.JarEntry;
1515
import java.util.jar.JarFile;
1616
import java.util.regex.Pattern;
17+
import org.springframework.instrument.InstrumentationSavingAgent;
1718

1819
public class LauncherAgent {
1920
private static Instrumentation instrumentation;
@@ -24,7 +25,7 @@ public static void agentmain(String agentArgs, Instrumentation inst) {
2425

2526
public static void premain(String agentArgs, Instrumentation inst) {
2627
System.out.println("Launcher-Agent started. Loading actual agent...");
27-
// InstrumentationSavingAgent.premain(agentArgs, inst);
28+
InstrumentationSavingAgent.premain(agentArgs, inst);
2829
instrumentation = inst;
2930
// launchSparkHook(agentArgs, inst);
3031
}

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/__AdditionalSpringStandaloneConfiguration.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import dev.slne.surf.cloud.api.server.plugin.AdditionalStandaloneConfiguration
44
import dev.slne.surf.cloud.api.server.plugin.TransactionConfiguration
55
import org.jetbrains.exposed.spring.autoconfigure.ExposedAutoConfiguration
66
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
7-
import org.springframework.context.annotation.EnableAspectJAutoProxy
87
import org.springframework.context.annotation.Import
98

109
/**
@@ -15,5 +14,5 @@ import org.springframework.context.annotation.Import
1514
@AdditionalStandaloneConfiguration
1615
@ImportAutoConfiguration(ExposedAutoConfiguration::class)
1716
@Import(TransactionConfiguration::class)
18-
@EnableAspectJAutoProxy(proxyTargetClass = true)
17+
//@EnableAspectJAutoProxy(proxyTargetClass = true)
1918
internal class __AdditionalSpringStandaloneConfiguration

0 commit comments

Comments
 (0)