KsContext
Meta-annotation that opts an annotation class into ksrpc's per-call coroutine-context propagation. Apply this to an annotation class together with a binding referencing a concrete KsContextBinding implementation to declare that the annotated KsMethod (or every KsMethod inside an annotated KsService) should propagate a kotlin.coroutines.CoroutineContext.Element value across the wire.
The binding supplies:
A stable wire-level key (KsContextBinding.wireKey) used by transport layers to encode the value.
The kotlin.coroutines.CoroutineContext.Key identity itself — KsContextBinding extends kotlin.coroutines.CoroutineContext.Key, so handlers find the propagated value via the standard
coroutineContext[SomeBinding]lookup naming the binding directly.String encode / decode functions (KsContextBinding.toWire / KsContextBinding.fromWire) used by transport layers that carry the context value as a textual representation.
Compiler validation:
The plugin rejects a
@KsContext-meta-annotated annotation whose binding does not implement KsContextBinding.The plugin rejects a KsMethod (or its enclosing KsService) when two
@KsContext-meta-annotated annotations apply whose bindings declare the same KsContextBinding.wireKey.
Code emission for stub-side put-into-context and handler-side read-from-coroutine-context, plus per-transport wire formats, is handled by follow-up work and is intentionally not part of this annotation's contract.
Samples
import com.monkopedia.ksrpc.KsContextBinding
import com.monkopedia.ksrpc.RpcService
import com.monkopedia.ksrpc.annotation.KsContext
import com.monkopedia.ksrpc.annotation.KsMethod
import com.monkopedia.ksrpc.annotation.KsService
import com.monkopedia.ksrpc.ksrpcEnvironment
import com.monkopedia.ksrpc.serialized
import com.monkopedia.ksrpc.toStub
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlinx.coroutines.withContext
fun main() {
//sampleStart
// A KsContextBinding pairs a CoroutineContext.Element with a wire key.
// Declare the binding as a named companion on the element type.
val wireKey = RequestId.Key.wireKey // "x-request-id"
// Round-trip: encode to wire, decode from wire
val original = RequestId("abc-123")
val encoded = RequestId.Key.toWire(original)
val decoded = RequestId.Key.fromWire(encoded)
//sampleEnd
}import com.monkopedia.ksrpc.KsContextBinding
import com.monkopedia.ksrpc.RpcService
import com.monkopedia.ksrpc.annotation.KsContext
import com.monkopedia.ksrpc.annotation.KsMethod
import com.monkopedia.ksrpc.annotation.KsService
import com.monkopedia.ksrpc.ksrpcEnvironment
import com.monkopedia.ksrpc.serialized
import com.monkopedia.ksrpc.toStub
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlinx.coroutines.withContext
fun main() {
//sampleStart
// @KsContext is a meta-annotation applied to your own annotation.
// Apply the annotation at the service level (all methods) or per-method.
//
// @Authorized -- applied to SecureService (all methods get it)
// @WithRequestId -- applied to whoAmI only
//
// The compiler plugin validates that bindings implement KsContextBinding
// and that no two bindings share the same wireKey on a single method.
//sampleEnd
}import com.monkopedia.ksrpc.KsContextBinding
import com.monkopedia.ksrpc.RpcService
import com.monkopedia.ksrpc.annotation.KsContext
import com.monkopedia.ksrpc.annotation.KsMethod
import com.monkopedia.ksrpc.annotation.KsService
import com.monkopedia.ksrpc.ksrpcEnvironment
import com.monkopedia.ksrpc.serialized
import com.monkopedia.ksrpc.toStub
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlinx.coroutines.withContext
fun main() {
//sampleStart
// Server handler reads context from the coroutine context.
val service = object : SecureService {
override suspend fun whoAmI(input: String): String {
val auth = coroutineContext[AuthorizationToken.Key]
val reqId = coroutineContext[RequestId.Key]
return "auth=${auth?.bearer}, reqId=${reqId?.value}"
}
}
val env = ksrpcEnvironment { }
val serialized = service.serialized(env)
val stub = serialized.toStub<SecureService, String>()
// Client installs context elements using standard withContext.
// The ksrpc runtime propagates bound elements across the wire.
withContext(AuthorizationToken("secret-token") + RequestId("req-42")) {
val result = stub.whoAmI("hello")
}
//sampleEnd
}