Skip to content

Commit 9870406

Browse files
committed
Restore ThreadLocal context in coroutine
1 parent d330671 commit 9870406

File tree

4 files changed

+93
-6
lines changed

4 files changed

+93
-6
lines changed

core/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@
6464
<version>1.4.10</version>
6565
<scope>provided</scope>
6666
</dependency>
67+
<dependency>
68+
<groupId>org.jetbrains.kotlinx</groupId>
69+
<artifactId>kotlinx-coroutines-core</artifactId>
70+
<version>1.3.9</version>
71+
<scope>provided</scope>
72+
</dependency>
6773
</dependencies>
6874
<build>
6975
<plugins>

core/src/main/java/co/aikar/commands/RegisteredCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ void invoke(CommandIssuer sender, List<String> args, CommandOperationContext con
176176
Object[] methodArgsCopy = new Object[methodArgs.length + 1];
177177
System.arraycopy(methodArgs, 0, methodArgsCopy, 0, methodArgs.length);
178178
methodArgs = methodArgsCopy;
179-
methodArgs[methodArgs.length - 1] = new JavaContinuation<Object>() {
179+
ThreadLocalRestorer threadLocalRestorer = new ThreadLocalRestorer(CommandManager.commandOperationContext.get().peek());
180+
methodArgs[methodArgs.length - 1] = new JavaContinuation<Object>(threadLocalRestorer) {
180181
@Override
181182
public void resumeWithException(@NotNull Throwable exception) {
182183
handleException(sender, args, exception);
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2016-2020 Daniel Ennis (Aikar) - MIT License
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the
6+
* "Software"), to deal in the Software without restriction, including
7+
* without limitation the rights to use, copy, modify, merge, publish,
8+
* distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so, subject to
10+
* the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be
13+
* included in all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*/
23+
24+
package co.aikar.commands;
25+
26+
import kotlin.coroutines.CoroutineContext;
27+
import kotlin.jvm.functions.Function2;
28+
import kotlinx.coroutines.ThreadContextElement;
29+
import org.jetbrains.annotations.NotNull;
30+
import org.jetbrains.annotations.Nullable;
31+
32+
public final class ThreadLocalRestorer implements ThreadContextElement<Void> {
33+
34+
private final CommandOperationContext context;
35+
private final Key key = new Key();
36+
37+
public ThreadLocalRestorer(CommandOperationContext context) {
38+
this.context = context;
39+
}
40+
41+
@Override
42+
public void restoreThreadContext(@NotNull CoroutineContext coroutineContext, Void unused) {
43+
CommandManager.commandOperationContext.get().pop();
44+
}
45+
46+
@Override
47+
public Void updateThreadContext(@NotNull CoroutineContext coroutineContext) {
48+
CommandManager.commandOperationContext.get().push(this.context);
49+
return null;
50+
}
51+
52+
@NotNull
53+
@Override
54+
public CoroutineContext plus(@NotNull CoroutineContext coroutineContext) {
55+
return DefaultImpls.plus(this, coroutineContext);
56+
}
57+
58+
@NotNull
59+
@Override
60+
public Key getKey() {
61+
return this.key;
62+
}
63+
64+
@Override
65+
public <R> R fold(R r, @NotNull Function2<? super R, ? super Element, ? extends R> function2) {
66+
return DefaultImpls.fold(this, r, function2);
67+
}
68+
69+
@Nullable
70+
@Override
71+
public <E extends Element> E get(@NotNull CoroutineContext.Key<E> key) {
72+
return DefaultImpls.get(this, key);
73+
}
74+
75+
@NotNull
76+
@Override
77+
public CoroutineContext minusKey(@NotNull CoroutineContext.Key key) {
78+
return DefaultImpls.minusKey(this, key);
79+
}
80+
81+
public static final class Key implements kotlin.coroutines.CoroutineContext.Key<ThreadLocalRestorer> {
82+
}
83+
}

core/src/main/java/co/aikar/commands/kotlin/JavaContinuation.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,11 @@ import kotlin.coroutines.Continuation
2727
import kotlin.coroutines.CoroutineContext
2828
import kotlin.coroutines.EmptyCoroutineContext
2929

30-
abstract class JavaContinuation<T> : Continuation<T> {
31-
override val context: CoroutineContext
32-
get() = EmptyCoroutineContext
33-
30+
abstract class JavaContinuation<T>(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<T> {
3431
override fun resumeWith(result: Result<T>) {
3532
result.fold(::resume, ::resumeWithException)
3633
}
3734

3835
abstract fun resume(result: T)
3936
abstract fun resumeWithException(exception: Throwable)
40-
}
37+
}

0 commit comments

Comments
 (0)