11package dev.slne.surf.cloud.core.common.netty.registry.listener
22
3- import dev.slne.surf.cloud.api.common.netty.exception.SurfNettyListenerRegistrationException
43import dev.slne.surf.cloud.api.common.netty.packet.NettyPacket
54import dev.slne.surf.cloud.api.common.netty.packet.NettyPacketInfo
6- import tech.hiddenproject.aide.reflection.LambdaWrapperHolder
7- import tech.hiddenproject.aide.reflection.annotation.Invoker
5+ import net.bytebuddy.ByteBuddy
6+ import net.bytebuddy.description.method.MethodDescription
7+ import net.bytebuddy.dynamic.loading.ClassLoadingStrategy
8+ import net.bytebuddy.implementation.FieldAccessor
9+ import net.bytebuddy.implementation.MethodCall
10+ import net.bytebuddy.implementation.bytecode.assign.Assigner
11+ import net.bytebuddy.matcher.ElementMatchers
812import java.lang.reflect.Method
13+ import java.lang.reflect.Modifier
914
1015class RegisteredListener (
1116 private val bean : Any ,
12- listenerMethod : Method ,
17+ private val listenerMethod : Method ,
1318 packetClassIndex : Int ,
1419 packetInfoIndex : Int ,
1520 private val suspending : Boolean
1621) {
17- private var invoker: Any
22+ val owner: Any get() = bean
23+
24+ private val invoker: Any
1825 private val invokerType: InvokerType
1926
2027 init {
2128 val params = listenerMethod.parameterTypes
22-
23- if (params.size == 1 || (params.size == 2 && suspending)) { // Only NettyPacket
24- val clazz =
25- if (suspending) RegisteredListenerSuspendInvoker1 ::class else RegisteredListenerInvoker1 ::class
26-
27- this .invoker = LambdaWrapperHolder .DEFAULT .wrap(listenerMethod, clazz.java).wrapper
28- this .invokerType = InvokerType .ONE_PARAM
29- } else if (params.size == 2 || (params.size == 3 && suspending)) { // NettyPacket and NettyPacketInfo
30- if (packetClassIndex == 0 && packetInfoIndex == 1 ) { // Normal order (NettyPacket, NettyPacketInfo)
31- val clazz =
32- if (suspending) RegisteredListenerSuspendInvoker2 ::class else RegisteredListenerInvoker2 ::class
33-
34- this .invoker = LambdaWrapperHolder .DEFAULT .wrap(listenerMethod, clazz.java).wrapper
35- this .invokerType = InvokerType .TWO_PARAMS
36- } else if (packetInfoIndex == 0 && packetClassIndex == 1 ) { // Reversed order (NettyPacketInfo, NettyPacket)
37- val clazz =
38- if (suspending) RegisteredListenerSuspendInvoker2Rev ::class else RegisteredListenerInvoker2Rev ::class
39-
40- this .invoker = LambdaWrapperHolder .DEFAULT .wrap(listenerMethod, clazz.java).wrapper
41- this .invokerType = InvokerType .TWO_PARAMS_REVERSED
42- } else {
43- throw SurfNettyListenerRegistrationException (" Invalid parameter order" )
44- }
29+ val beanLoader: ClassLoader = bean.javaClass.classLoader
30+
31+ if (params.size == 1 || (params.size == 2 && suspending)) {
32+ invokerType = InvokerType .ONE_PARAM
33+ invoker = generateInvoker(
34+ iface = if (suspending) RegisteredListenerSuspendInvoker1 ::class .java else RegisteredListenerInvoker1 ::class .java,
35+ loader = beanLoader,
36+ ownerArg = bean,
37+ paramOrder = if (suspending) intArrayOf(1 , 2 ) else intArrayOf(1 )
38+ )
39+ } else if (params.size == 2 || (params.size == 3 && suspending)) {
40+ val reversed = packetInfoIndex == 0 && packetClassIndex == 1
41+ invokerType = if (reversed) InvokerType .TWO_PARAMS_REVERSED else InvokerType .TWO_PARAMS
42+ invoker = generateInvoker(
43+ iface = when {
44+ suspending && ! reversed -> RegisteredListenerSuspendInvoker2 ::class .java
45+ suspending && reversed -> RegisteredListenerSuspendInvoker2Rev ::class .java
46+ ! suspending && ! reversed -> RegisteredListenerInvoker2 ::class .java
47+ else -> RegisteredListenerInvoker2Rev ::class .java
48+ },
49+ loader = beanLoader,
50+ ownerArg = bean,
51+ paramOrder = when {
52+ suspending && ! reversed -> intArrayOf(1 , 2 , 3 ) // packet, info, cont
53+ suspending && reversed -> intArrayOf(2 , 1 , 3 ) // info, packet, cont
54+ ! suspending && ! reversed -> intArrayOf(1 , 2 ) // packet, info
55+ else -> intArrayOf(2 , 1 ) // info, packet
56+ }
57+ )
4558 } else {
46- throw SurfNettyListenerRegistrationException (" Invalid number of parameters" )
59+ error (" Invalid number of parameters for listener method: ${listenerMethod.name} in ${bean.javaClass.name} . Method must take exactly one parameter of type NettyPacket or two parameters of type NettyPacket and NettyPacketInfo. " )
4760 }
4861 }
4962
50- suspend fun handle (packet : NettyPacket , info : NettyPacketInfo ) = when (invokerType) {
51- InvokerType . ONE_PARAM -> {
52- if (suspending) {
63+ suspend fun handle (packet : NettyPacket , info : NettyPacketInfo ) {
64+ when (invokerType) {
65+ InvokerType . ONE_PARAM -> if (suspending) {
5366 (invoker as RegisteredListenerSuspendInvoker1 ).handle(bean, packet)
5467 } else {
5568 (invoker as RegisteredListenerInvoker1 ).handle(bean, packet)
5669 }
57- }
5870
59- InvokerType .TWO_PARAMS -> {
60- if (suspending) {
71+ InvokerType .TWO_PARAMS -> if (suspending) {
6172 (invoker as RegisteredListenerSuspendInvoker2 ).handle(bean, packet, info)
6273 } else {
6374 (invoker as RegisteredListenerInvoker2 ).handle(bean, packet, info)
6475 }
65- }
6676
67- InvokerType .TWO_PARAMS_REVERSED -> {
68- if (suspending) {
77+ InvokerType .TWO_PARAMS_REVERSED -> if (suspending) {
6978 (invoker as RegisteredListenerSuspendInvoker2Rev ).handle(bean, info, packet)
7079 } else {
7180 (invoker as RegisteredListenerInvoker2Rev ).handle(bean, info, packet)
7281 }
7382 }
83+
84+ }
85+
86+ private fun <I > generateInvoker (
87+ iface : Class <I >,
88+ loader : ClassLoader ,
89+ ownerArg : Any ,
90+ paramOrder : IntArray
91+ ): I {
92+ val baseCall = if (Modifier .isStatic(listenerMethod.modifiers)) {
93+ MethodCall .invoke(listenerMethod).on(listenerMethod.declaringClass)
94+ } else {
95+ MethodCall .invoke(listenerMethod).onArgument(0 )
96+ }
97+ val callWithArgs = paramOrder.fold(baseCall) { acc, idx -> acc.withArgument(idx) }
98+ val finalCall = callWithArgs.withAssigner(
99+ Assigner .DEFAULT ,
100+ Assigner .Typing .DYNAMIC
101+ )
102+
103+ val dynamicType = ByteBuddy ()
104+ .subclass(Any ::class .java)
105+ .implement(iface)
106+ .defineField(" owner" , Any ::class .java, Modifier .PRIVATE or Modifier .FINAL )
107+ .defineConstructor(Modifier .PUBLIC )
108+ .withParameters(Any ::class .java)
109+ .intercept(
110+ MethodCall .invoke(Object ::class .java.getConstructor())
111+ .andThen(FieldAccessor .ofField(" owner" ).setsArgumentAt(0 ))
112+ )
113+ .method(
114+ ElementMatchers .named<MethodDescription >(" handle" )
115+ .and (ElementMatchers .isDeclaredBy(iface))
116+ )
117+ .intercept(finalCall)
118+ .make()
119+ .load(loader, ClassLoadingStrategy .Default .INJECTION )
120+ .loaded
121+
122+ val constructor = dynamicType.getDeclaredConstructor(Any ::class .java)
123+
124+ @Suppress(" UNCHECKED_CAST" )
125+ return constructor .newInstance(ownerArg) as I
74126 }
75127
76128 private enum class InvokerType {
@@ -79,48 +131,27 @@ class RegisteredListener(
79131 TWO_PARAMS_REVERSED
80132 }
81133
82- // region Standard Invokers
83134 fun interface RegisteredListenerInvoker1 {
84- @Invoker
85135 fun handle (caller : Any , packet : NettyPacket )
86136 }
87137
88138 fun interface RegisteredListenerInvoker2 {
89- @Invoker
90139 fun handle (caller : Any , packet : NettyPacket , info : NettyPacketInfo )
91140 }
92141
93142 fun interface RegisteredListenerInvoker2Rev {
94- @Invoker
95143 fun handle (caller : Any , info : NettyPacketInfo , packet : NettyPacket )
96144 }
97- // endregion
98145
99- // region Suspend Invokers for Kotlin coroutines
100146 fun interface RegisteredListenerSuspendInvoker1 {
101- @Invoker
102147 suspend fun handle (caller : Any , packet : NettyPacket )
103148 }
104149
105150 fun interface RegisteredListenerSuspendInvoker2 {
106- @Invoker
107151 suspend fun handle (caller : Any , packet : NettyPacket , info : NettyPacketInfo )
108152 }
109153
110154 fun interface RegisteredListenerSuspendInvoker2Rev {
111- @Invoker
112155 suspend fun handle (caller : Any , info : NettyPacketInfo , packet : NettyPacket )
113156 }
114- // endregion
115-
116- companion object {
117- init {
118- LambdaWrapperHolder .DEFAULT .add(RegisteredListenerInvoker1 ::class .java)
119- LambdaWrapperHolder .DEFAULT .add(RegisteredListenerInvoker2 ::class .java)
120- LambdaWrapperHolder .DEFAULT .add(RegisteredListenerInvoker2Rev ::class .java)
121- LambdaWrapperHolder .DEFAULT .add(RegisteredListenerSuspendInvoker1 ::class .java)
122- LambdaWrapperHolder .DEFAULT .add(RegisteredListenerSuspendInvoker2 ::class .java)
123- LambdaWrapperHolder .DEFAULT .add(RegisteredListenerSuspendInvoker2Rev ::class .java)
124- }
125- }
126- }
157+ }
0 commit comments