Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.5.0 #249

Merged
merged 13 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ permissions:
env:
INSTANCE: 'kotlinx-rpc/rpc'
ARTIFACT: 'webHelpRPC2-all.zip'
DOCKER_VERSION: '241.15989'
DOCKER_VERSION: '243.22562'
ALGOLIA_ARTIFACT: 'algolia-indexes-RPC.zip'
ALGOLIA_APP_NAME: 'MMA5Z3JT91'
ALGOLIA_INDEX_NAME: 'prod_kotlin_rpc'
ALGOLIA_KEY: '${{ secrets.ALGOLIA_KEY }}'
CONFIG_JSON_PRODUCT: 'kotlinx-rpc'
CONFIG_JSON_VERSION: '0.4.0'
CONFIG_JSON_VERSION: '0.5.0'

jobs:
build:
Expand Down
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
# 0.5.0
> Published 27 January 2024

### Features 🎉
* Update Service Descriptors Generation by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/227
* Kotlin 2.1.0 by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/244
* Added basic CheckedTypeAnnotation impl with compiler plugin check by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/240
* Strict mode by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/243

### Breaking Changes 🔴
* Api naming by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/236
* Update Service Descriptors Generation by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/227
* Added basic CheckedTypeAnnotation impl with compiler plugin check by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/240

### Deprecations ⚠️
* Api naming by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/236
* Strict mode by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/243

### Infra 🚧
* Update the project structure to work with kotlin-master by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/234
* Fixed version formatting with ENV vars by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/235
* Fix Kotlin master compilation by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/245
* Opt-out from annotations type safety analysis by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/246

### Other Changes 🧹
* Added test for non-serializable params by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/237
* Updated descriptor to use `RpcType` instead of `KType` directly by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/239

**Full Changelog**: https://github.com/Kotlin/kotlinx-rpc/compare/0.4.0...0.5.0

# 0.4.0
> Published 5 November 2024

Expand Down
52 changes: 40 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,36 @@ import kotlinx.rpc.annotations.Rpc
@Rpc
interface AwesomeService : RemoteService {
suspend fun getNews(city: String): Flow<String>

suspend fun daysUntilStableRelese(): Int
}
```
In your server code define how to respond by simply implementing the service:
```kotlin
class AwesomeServiceImpl(override val coroutineContext: CoroutineContext) : AwesomeService {
class AwesomeServiceImpl(
val parameters: AwesomeParameters,
override val coroutineContext: CoroutineContext,
) : AwesomeService {
override suspend fun getNews(city: String): Flow<String> {
return flow {
emit("Today is 23 degrees!")
emit("Harry Potter is in $city!")
emit("New dogs cafe has opened doors to all fluffy customers!")
}
}

override suspend fun daysUntilStableRelese(): Int {
retuen if (parameters.stable) 0 else {
parameters.daysUntilStable ?: error("Who says it will be stable?")
}
}
}
```
Then, choose how do you want your service to communicate. For example, you can use integration with [Ktor](https://ktor.io/):

```kotlin
data class AwesomeParameters(val stable: Boolean, val daysUntilStable: Int?)

fun main() {
embeddedServer(Netty, 8080) {
install(Krpc)
Expand All @@ -53,7 +66,9 @@ fun main() {
}
}

registerService<AwesomeService> { ctx -> AwesomeServiceImpl(ctx) }
registerService<AwesomeService> { ctx ->
AwesomeServiceImpl(AwesomeParameters(false, null), ctx)
}
}
}
}.start(wait = true)
Expand All @@ -71,8 +86,12 @@ val rpcClient = HttpClient { installKrpc() }.rpc {
}
}

val service = rpcClient.withService<AwesomeService>()

service.daysUntilStableRelese()

streamScoped {
rpcClient.withService<AwesomeService>().getNews("KotlinBurg").collect { article ->
service.getNews("KotlinBurg").collect { article ->
println(article)
}
}
Expand All @@ -92,7 +111,7 @@ Example of a setup in a project's `build.gradle.kts`:
plugins {
kotlin("multiplatform") version "2.1.0"
kotlin("plugin.serialization") version "2.1.0"
id("org.jetbrains.kotlinx.rpc.plugin") version "0.4.0"
id("org.jetbrains.kotlinx.rpc.plugin") version "0.5.0"
}
```

Expand All @@ -107,15 +126,15 @@ And now you can add dependencies to your project:
```kotlin
dependencies {
// Client API
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-client:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-client:0.5.0")
// Server API
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-server:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-server:0.5.0")
// Serialization module. Also, protobuf and cbor are provided
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-serialization-json:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-serialization-json:0.5.0")

// Transport implementation for Ktor
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-ktor-client:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-ktor-server:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-ktor-client:0.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-rpc-krpc-ktor-server:0.5.0")

// Ktor API
implementation("io.ktor:ktor-client-cio-jvm:$ktor_version")
Expand All @@ -137,9 +156,18 @@ When using kRPC you only need to provide a transport or choose from the official

Besides that, one can even provide their own protocol or integration with one to use with services and `kotlinx.rpc` API with it.
Though possible, it is much more complicated way to use the library and generally not needed.
`kotlinx.rpc` aims to provide most common protocols integrations as well as the in-house one called kRPC.
Integrations in progress:
- Integration with [gRPC](https://grpc.io/) (in prototype)
`kotlinx.rpc` aims to provide support for the most common protocol integrations, as well as the in-house protocol called kRPC.

## gRPC integration
The library provides experimental support for the [gRPC](https://grop.io) protocol.
The artifacts are published separately in our [Space repository](https://public.jetbrains.space/p/krpc/packages/maven/grpc).
Current latest version:

![Dynamic XML Badge](https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fpublic%2Fp%2Fkrpc%2Fgrpc%2Forg%2Fjetbrains%2Fkotlinx%2Fkotlinx-rpc-core%2Fmaven-metadata.xml&query=%2F%2Fmetadata%2Fversioning%2Flatest&label=Latest%20dev%20version&color=forest-green&cacheSeconds=60)

For more information on gRPC usage,
see the [official documentation](https://kotlin.github.io/kotlinx-rpc/grpc-configuration.html).
For a working example, see the [sample gRPC project](/samples/grpc-app).

## Kotlin compatibility
We support all stable Kotlin versions starting from 2.0.0:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc.codegen
Expand All @@ -12,6 +12,10 @@ object FirRpcPredicates {
annotated(RpcClassId.rpcAnnotation.asSingleFqName()) // @Rpc
}

internal val rpcMeta = DeclarationPredicate.create {
metaAnnotated(RpcClassId.rpcAnnotation.asSingleFqName(), includeItself = true)
}

internal val checkedAnnotationMeta = DeclarationPredicate.create {
metaAnnotated(RpcClassId.checkedTypeAnnotation.asSingleFqName(), includeItself = false)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc.codegen.checkers
Expand All @@ -9,7 +9,9 @@ import kotlinx.rpc.codegen.FirRpcPredicates
import kotlinx.rpc.codegen.checkers.diagnostics.FirRpcDiagnostics
import kotlinx.rpc.codegen.isRemoteService
import kotlinx.rpc.codegen.remoteServiceSupertypeSource
import kotlinx.rpc.codegen.rpcAnnotation
import kotlinx.rpc.codegen.rpcAnnotationSource
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
Expand All @@ -18,6 +20,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirRegularClassChe
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.types.resolvedType

class FirRpcAnnotationChecker(private val ctx: FirCheckersContext) : FirRegularClassChecker(MppCheckerKind.Common) {
override fun check(
Expand All @@ -26,12 +29,15 @@ class FirRpcAnnotationChecker(private val ctx: FirCheckersContext) : FirRegularC
reporter: DiagnosticReporter,
) {
val rpcAnnotated = context.session.predicateBasedProvider.matches(FirRpcPredicates.rpc, declaration)
val rpcMetaAnnotated = context.session.predicateBasedProvider.matches(FirRpcPredicates.rpcMeta, declaration)

if (!declaration.isInterface && rpcAnnotated) {
if (!declaration.isInterface && declaration.classKind != ClassKind.ANNOTATION_CLASS && rpcMetaAnnotated) {
reporter.reportOn(
source = declaration.symbol.rpcAnnotationSource(context.session),
factory = FirRpcDiagnostics.WRONG_RPC_ANNOTATION_TARGET,
context = context,
a = declaration.symbol.rpcAnnotation(context.session)?.resolvedType
?: error("Unexpected unresolved annotation type for declaration: ${declaration.symbol.classId.asSingleFqName()}"),
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc.codegen.checkers.diagnostics
Expand All @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.psi.KtAnnotationEntry
object FirRpcDiagnostics {
val MISSING_RPC_ANNOTATION by error0<KtAnnotationEntry>()
val MISSING_SERIALIZATION_MODULE by warning0<KtAnnotationEntry>()
val WRONG_RPC_ANNOTATION_TARGET by error0<KtAnnotationEntry>()
val WRONG_RPC_ANNOTATION_TARGET by error1<KtAnnotationEntry, ConeKotlinType>()
val CHECKED_ANNOTATION_VIOLATION by error1<KtAnnotationEntry, ConeKotlinType>()
val NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE by error0<PsiElement>()
val AD_HOC_POLYMORPHISM_IN_RPC_SERVICE by error2<PsiElement, Int, Name>()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc.codegen.checkers.diagnostics
Expand Down Expand Up @@ -29,7 +29,8 @@ object RpcDiagnosticRendererFactory : BaseDiagnosticRendererFactory() {

put(
factory = FirRpcDiagnostics.WRONG_RPC_ANNOTATION_TARGET,
message = "@Rpc annotation is only applicable to interfaces.",
message = "@{0} annotation is only applicable to interfaces and annotation classes.",
rendererA = FirDiagnosticRenderers.RENDER_TYPE,
)

put(
Expand Down
5 changes: 4 additions & 1 deletion core/src/commonMain/kotlin/kotlinx/rpc/RpcCall.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc

import kotlinx.rpc.descriptor.RpcServiceDescriptor

@Deprecated("Use RpcCall instead", ReplaceWith("RpcCall"), level = DeprecationLevel.ERROR)
public typealias RPCCall = RpcCall

/**
* Represents a method or field call of an RPC service.
*
Expand Down
5 changes: 4 additions & 1 deletion core/src/commonMain/kotlin/kotlinx/rpc/RpcClient.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc
Expand All @@ -8,6 +8,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlin.coroutines.CoroutineContext

@Deprecated("Use RpcClient instead", ReplaceWith("RpcClient"), level = DeprecationLevel.ERROR)
public typealias RPCClient = RpcClient

/**
* [RpcClient] represents an abstraction of an RPC client, that can handle requests from several RPC services,
* transform them, send to the server and handle responses and errors.
Expand Down
6 changes: 5 additions & 1 deletion core/src/commonMain/kotlin/kotlinx/rpc/RpcEagerField.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc
Expand All @@ -8,6 +8,10 @@ package kotlinx.rpc
* The field marked with this annotation will be initialized with the service creation.
*/
@Target(AnnotationTarget.PROPERTY)
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public annotation class RpcEagerField

@Deprecated("Use RpcEagerField instead", ReplaceWith("RpcEagerField"), level = DeprecationLevel.ERROR)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc
Expand All @@ -18,6 +18,10 @@ public typealias UninitializedRPCFieldException = UninitializedRpcFieldException
*
* Use [awaitFieldInitialization] to await for the field initialization
*/
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public class UninitializedRpcFieldException(serviceName: String, property: KProperty<*>) : Exception() {
override val message: String = "${property.name} field of RPC service \"$serviceName\" in not initialized"
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc
Expand Down Expand Up @@ -27,6 +27,10 @@ import kotlin.reflect.KClass
* @param getter function that returns the field of the context service to wait for.
* @return service filed after it was initialized.
*/
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public suspend fun <@Rpc T : Any, R> T.awaitFieldInitialization(getter: T.() -> R): R {
val field = getter()

Expand Down Expand Up @@ -56,6 +60,10 @@ public suspend fun <@Rpc T : Any, R> T.awaitFieldInitialization(getter: T.() ->
* @param T service type
* @return specified service, after all of it's field were initialized.
*/
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public suspend inline fun <@Rpc reified T : Any> T.awaitFieldInitialization(): T {
return awaitFieldInitialization(T::class)
}
Expand All @@ -79,6 +87,10 @@ public suspend inline fun <@Rpc reified T : Any> T.awaitFieldInitialization(): T
* @param kClass [KClass] of the [T] type.
* @return specified service, after all of it's field were initialized.
*/
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public suspend fun <@Rpc T : Any> T.awaitFieldInitialization(kClass: KClass<T>): T {
serviceDescriptorOf(kClass)
.getFields(this)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc.descriptor
Expand Down Expand Up @@ -44,6 +44,10 @@ public interface RpcServiceDescriptor<@Rpc T : Any> {
public val fqName: String

@InternalRpcApi
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public fun getFields(service: T): List<RpcDeferredField<*>>

public fun getCallable(name: String): RpcCallable<T>?
Expand All @@ -68,6 +72,10 @@ public sealed interface RpcInvokator<@Rpc T : Any> {
}

@ExperimentalRpcApi
@Deprecated(
"Fields are deprecated, see https://kotlin.github.io/kotlinx-rpc/0-5-0.html",
level = DeprecationLevel.WARNING,
)
public fun interface Field<@Rpc T : Any> : RpcInvokator<T> {
public fun call(service: T): Any?
}
Expand Down
Loading
Loading