{"id":13625080,"url":"https://github.com/marcoferrer/kroto-plus","last_synced_at":"2025-04-05T03:08:19.381Z","repository":{"id":37271542,"uuid":"124468545","full_name":"marcoferrer/kroto-plus","owner":"marcoferrer","description":"gRPC Kotlin Coroutines, Protobuf DSL, Scripting for Protoc","archived":false,"fork":false,"pushed_at":"2020-12-18T08:55:26.000Z","size":1233,"stargazers_count":491,"open_issues_count":32,"forks_count":29,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-03-29T02:04:11.423Z","etag":null,"topics":["code-generation","coroutines","grpc","grpc-java","grpc-kotlin","kotlin","kotlin-coroutines","kotlin-script","protobuf","protoc-grpc-plugin","protoc-plugin","protocol-buffers"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcoferrer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-09T01:14:41.000Z","updated_at":"2025-02-28T06:52:11.000Z","dependencies_parsed_at":"2022-09-26T21:41:26.825Z","dependency_job_id":null,"html_url":"https://github.com/marcoferrer/kroto-plus","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcoferrer%2Fkroto-plus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcoferrer%2Fkroto-plus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcoferrer%2Fkroto-plus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcoferrer%2Fkroto-plus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcoferrer","download_url":"https://codeload.github.com/marcoferrer/kroto-plus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247280269,"owners_count":20912967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generation","coroutines","grpc","grpc-java","grpc-kotlin","kotlin","kotlin-coroutines","kotlin-script","protobuf","protoc-grpc-plugin","protoc-plugin","protocol-buffers"],"created_at":"2024-08-01T21:01:50.583Z","updated_at":"2025-04-05T03:08:19.364Z","avatar_url":"https://github.com/marcoferrer.png","language":"Kotlin","funding_links":[],"categories":["Kotlin","Language-Specific"],"sub_categories":["Kotlin"],"readme":"![Kroto+](https://raw.githubusercontent.com/marcoferrer/kroto-plus/master/kp-logo.svg?sanitize=true)\n## gRPC Kotlin Coroutines, Protobuf DSL, Scripting for Protoc   \n[![Build Status](https://travis-ci.org/marcoferrer/kroto-plus.svg?branch=master)](https://travis-ci.org/marcoferrer/kroto-plus)\n[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)\n[![JCenter](https://api.bintray.com/packages/marcoferrer/kroto-plus/protoc-gen-kroto-plus/images/download.svg) ](https://bintray.com/marcoferrer/kroto-plus/protoc-gen-kroto-plus/_latestVersion)\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.marcoferrer.krotoplus/protoc-gen-kroto-plus.svg?label=Maven%20Central)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.marcoferrer.krotoplus%22%20a%3A%22protoc-gen-kroto-plus%22)\n[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)\n[![Awesome gRPC](https://img.shields.io/badge/awesome-gRPC-%232DA6B0.svg)](https://github.com/gRPC-ecosystem/awesome-grpc)\n[![Slack](https://img.shields.io/badge/Slack-%23kroto--plus-ECB22E.svg?logo=data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTQgNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMTkuNzEyLjEzM2E1LjM4MSA1LjM4MSAwIDAgMC01LjM3NiA1LjM4NyA1LjM4MSA1LjM4MSAwIDAgMCA1LjM3NiA1LjM4Nmg1LjM3NlY1LjUyQTUuMzgxIDUuMzgxIDAgMCAwIDE5LjcxMi4xMzNtMCAxNC4zNjVINS4zNzZBNS4zODEgNS4zODEgMCAwIDAgMCAxOS44ODRhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYgNS4zODdoMTQuMzM2YTUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2LTUuMzg3IDUuMzgxIDUuMzgxIDAgMCAwLTUuMzc2LTUuMzg2IiBmaWxsPSIjMzZDNUYwIi8+PHBhdGggZD0iTTUzLjc2IDE5Ljg4NGE1LjM4MSA1LjM4MSAwIDAgMC01LjM3Ni01LjM4NiA1LjM4MSA1LjM4MSAwIDAgMC01LjM3NiA1LjM4NnY1LjM4N2g1LjM3NmE1LjM4MSA1LjM4MSAwIDAgMCA1LjM3Ni01LjM4N20tMTQuMzM2IDBWNS41MkE1LjM4MSA1LjM4MSAwIDAgMCAzNC4wNDguMTMzYTUuMzgxIDUuMzgxIDAgMCAwLTUuMzc2IDUuMzg3djE0LjM2NGE1LjM4MSA1LjM4MSAwIDAgMCA1LjM3NiA1LjM4NyA1LjM4MSA1LjM4MSAwIDAgMCA1LjM3Ni01LjM4NyIgZmlsbD0iIzJFQjY3RCIvPjxwYXRoIGQ9Ik0zNC4wNDggNTRhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYtNS4zODcgNS4zODEgNS4zODEgMCAwIDAtNS4zNzYtNS4zODZoLTUuMzc2djUuMzg2QTUuMzgxIDUuMzgxIDAgMCAwIDM0LjA0OCA1NG0wLTE0LjM2NWgxNC4zMzZhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYtNS4zODYgNS4zODEgNS4zODEgMCAwIDAtNS4zNzYtNS4zODdIMzQuMDQ4YTUuMzgxIDUuMzgxIDAgMCAwLTUuMzc2IDUuMzg3IDUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2IDUuMzg2IiBmaWxsPSIjRUNCMjJFIi8+PHBhdGggZD0iTTAgMzQuMjQ5YTUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2IDUuMzg2IDUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2LTUuMzg2di01LjM4N0g1LjM3NkE1LjM4MSA1LjM4MSAwIDAgMCAwIDM0LjI1bTE0LjMzNi0uMDAxdjE0LjM2NEE1LjM4MSA1LjM4MSAwIDAgMCAxOS43MTIgNTRhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYtNS4zODdWMzQuMjVhNS4zODEgNS4zODEgMCAwIDAtNS4zNzYtNS4zODcgNS4zODEgNS4zODEgMCAwIDAtNS4zNzYgNS4zODciIGZpbGw9IiNFMDFFNUEiLz48L2c+PC9zdmc+\u0026labelColor=611f69)](https://kotlinlang.slack.com/messages/kroto-plus/)\n\n### Community Contributions are Welcomed\n\n\u003e ℹ️ | **Docs are being expanded and moved to [Readme.io](https://kroto-plus.readme.io/docs)**\n\n## Quick Start: gRPC Coroutines\nRun the following command to get started with a preconfigured template project. (_[kotlin-coroutines-gRPC-template](https://github.com/marcoferrer/kotlin-coroutines-gRPC-template)_)\n```bash\ngit clone https://github.com/marcoferrer/kotlin-coroutines-gRPC-template \u0026\u0026 \\\ncd kotlin-coroutines-gRPC-template \u0026\u0026 \\\n./gradlew run \n```\n\n## Getting Started\n* **[Gradle](https://github.com/marcoferrer/kroto-plus#getting-started-with-gradle)**\n* **[Maven](https://github.com/marcoferrer/kroto-plus#getting-started-with-maven)**\n\n## Code Generators\n\n* There are several built in code generators that each accept unique configuration options.\n* **[Configuration Setup](https://kroto-plus.readme.io/docs/configuration-file)**\n  * **[Proto Builder Generator](https://github.com/marcoferrer/kroto-plus#proto-builder-generator-message-dsl)**\n  * **[gRPC Coroutines Client \u0026 Server](https://github.com/marcoferrer/kroto-plus#grpc-coroutines-client--server)**\n  * **[gRPC Stub Extensions](https://github.com/marcoferrer/kroto-plus#grpc-stub-extensions)**\n    * **[Rpc Method Coroutine Support](https://github.com/marcoferrer/kroto-plus#coroutine-support)**\n  * **[Mock Service Generator](https://github.com/marcoferrer/kroto-plus#mock-service-generator)**\n  * **[Extendable Messages Generator](https://github.com/marcoferrer/kroto-plus#extendable-messages-generator-experimental)**\n  * **[User Defined Generator Scripts](https://github.com/marcoferrer/kroto-plus#user-defined-generator-scripts)**\n    * **[Insertion Scripts](https://github.com/marcoferrer/kroto-plus#insertion-scripts)**\n    * **[Generator Scripts](https://github.com/marcoferrer/kroto-plus#generator-scripts)**\n\n---\n\n### Proto Builder Generator (Message DSL)\n#### [Setup \u0026 Documentation](https://kroto-plus.readme.io/docs/protobuf-message-dsl)\nThis generator creates lambda based builders for message types\n\n```kotlin\n     val starPlatinum = Stand {\n        name = \"Star Platinum\"\n        powerLevel = 500\n        speed = 550\n        attack {\n            name = \"ORA ORA ORA\"\n            damage = 100\n            range = Attack.Range.CLOSE\n        }\n    }\n    \n    val attack = Attack {\n        name = \"ORA ORA ORA\"\n        damage = 100\n        range = Attack.Range.CLOSE\n    }\n    \n    // Copy extensions\n    val newAttack = attack.copy { damage = 200 }            \n    \n    // orDefault() will return the messages default instance when null\n    val nullableAttack: Attack? = null\n    nullableAttack.orDefault()\n    \n    // Plus operator extensions \n    val mergedAttack = attack + Attack { name = \"Sunlight Yellow Overdrive\" }            \n```\n---\n\n### gRPC Coroutines Client \u0026 Server \u0026nbsp;\u0026nbsp; [![codecov](https://codecov.io/gh/marcoferrer/kroto-plus/branch/master/graph/badge.svg)](https://codecov.io/gh/marcoferrer/kroto-plus)\nThis option requires the artifact ```kroto-plus-coroutines``` as a dependency.\n#### [Configuration Options](https://github.com/marcoferrer/kroto-plus/blob/master/docs/markdown/kroto-plus-config.md#grpccoroutinesgenoptions)\n\n[Client / Server Examples](https://github.com/marcoferrer/kroto-plus#examples)  \n[Method Signature Option Support](#method-signature-options-support)  \n\n* Design\n  * **Back pressure** is supported via [Manual Flow Control](https://github.com/grpc/grpc-java/tree/master/examples/src/main/java/io/grpc/examples/manualflowcontrol)\n    * Related Reading: [Understanding Reactive gRPC Flow Control](https://github.com/salesforce/reactive-grpc#back-pressure)\n  * **Cooperative cancellation** across network boundaries.\n\u003ca\u003e\u003c/a\u003e\n* Client Stubs\n  * Designed to work well with **Structured Concurrency**\n  * Cancellation of the client `CoroutineScope` will propagate to the server.\n  * Cancellations can now be propagated across usages of a specific stub instance.\n  * Rpc methods are overloaded with inline builders for request types\n  * The request parameter for rpc methods defaults to `RequestType.defaultsInstance`\n \n       \n```kotlin\n// Creates new stub with a default coroutine context of `EmptyCoroutineContext`\nval stub = GreeterCoroutineGrpc.newStub(channel)\n\n// Suspends and creates new stub using the current coroutine context as the default. \nval stub = GreeterCoroutineGrpc.newStubWithContext(channel)\n\n// An existing stub can replace its current coroutine context using either \nstub.withCoroutineContext()\nstub.withCoroutineContext(coroutineContext)\n\n// Stubs can accept message builder lambdas as an argument  \nstub.sayHello { name = \"John\" }\n\n// For more idiomatic usage in coroutines, stubs can be created\n// with an explicit coroutine scope using the `newGrpcStub` scope extension function.\nlaunch {\n    // Using `newGrpcStub` makes it clear that the resulting stub will use the receiving \n    // coroutine scope to launch any concurrent work. (usually for manual flow control in streaming apis) \n    val stub = newGrpcStub(GreeterCoroutineGrpc.GreeterCoroutineStub, channel)\n    \n    val (requestChannel, responseChannel) = stub.sayHelloStreaming()\n    ...\n}\n\n\n```  \n  * Service Base Impl\n    * Rpc calls are wrapped within a scope initialized with the following context elements.\n      * ```CoroutineName``` set to ```MethodDescriptor.fullMethodName```\n      * ```GrpcContextElement``` set to ```io.grpc.Context.current()```\n    * Base services implement ```ServiceScope``` and allow overriding the initial ```coroutineContext``` used for each rpc method invocation.\n    * Each services ```initialContext``` defaults to ```EmptyCoroutineContext```\n    * A common case for overriding the ```initialContext``` is for setting up application specific ```ThreadContextElement``` or ```CoroutineDispatcher```, such as ```MDCContext()``` or ```newFixedThreadPoolContext(...)```\n    \n#### Cancellation Propagation\n  * Client\n    * Both normal and exceptional coroutine scope cancellation will cancel the underlying call stream. See `ClientCall.cancel()` in [io.grpc.ClientCall.java](https://github.com/grpc/grpc-java/blob/master/core/src/main/java/io/grpc/ClientCall.java#214) for more details.\n    * In the case of service implementations using coroutines, this client call stream cancellation will cancel the coroutine scope of the rpc method being invoked on the server.\n  * Server\n    * Exceptional cancellation of the coroutine scope for the rpc method will be mapped to an instance of `StatusRuntimeException` and returned to the client.\n    * Normal cancellation of the coroutine scope for the rpc method will be mapped to an instance of `StatusRuntimeException` with a status of `Status.CANCELLED`, and returned to the client. \n    * Cancellation signals from the corresponding client will cancel the coroutine scope of the rpc method being invoked.\n    \n\n#### Examples\n* [Unary](https://github.com/marcoferrer/kroto-plus#unary)\n* [Client Streaming](https://github.com/marcoferrer/kroto-plus#client-streaming)\n* [Server Streaming](https://github.com/marcoferrer/kroto-plus#server-streaming)\n* [Bi-Directional Streaming](https://github.com/marcoferrer/kroto-plus#bi-directional-streaming)\n  \n#### Unary\n**_Client_**: Unary calls will suspend until a response is received from the corresponding server. In the event of a cancellation or the server responds with an error the call will throw the appropriate `StatusRuntimeException` \n```kotlin\nval response = stub.sayHello { name = \"John\" }\n```\n**_Server_**: Unary rpc methods can respond to client requests by either returning the expected response type, or throwing an exception. \n```kotlin\noverride suspend fun sayHello(request: HelloRequest): HelloReply {\n\n    if (isValid(request.name))\n        return HelloReply { message = \"Hello there, ${request.name}!\" } else\n        throw Status.INVALID_ARGUMENT.asRuntimeException()\n}\n```\n\n#### Client Streaming\n**_Client_**: `requestChannel.send()` will suspend until the corresponding server signals it is ready by requesting a message. In the event of a cancellation or the server responds with an error, both `requestChannel.send()` and `response.await()`, will throw the appropriate `StatusRuntimeException`.   \n```kotlin\nval (requestChannel, response) = stub.sayHelloClientStreaming()\n\nlaunchProducerJob(requestChannel){\n    repeat(5){\n        send { name = \"name #$it\" }\n    }\n}\n\nprintln(\"Client Streaming Response: ${response.await()}\")\n```\n**_Server_**: Client streaming rpc methods can respond to client requests by either returning the expected response type, or throwing an exception. Calls to `requestChannel.receive()` will suspend and notify the corresponding client that the server is ready to accept a message. \n```kotlin\noverride suspend fun sayHelloClientStreaming(\n    requestChannel: ReceiveChannel\u003cHelloRequest\u003e\n): HelloReply =  HelloReply {\n    message = requestChannel.toList().joinToString()\n}\n```\n \n\n#### Server Streaming\n**_Client_**: `responseChannel.receive()` will suspend and notify the corresponding server that the client is ready to accept a message.\n```kotlin\nval responseChannel = stub.sayHelloServerStreaming { name = \"John\" }\n\nresponseChannel.consumeEach {\n    println(\"Server Streaming Response: $it\")\n}\n```\n**_Server_**: Server streaming rpc methods can respond to client requests by submitting messages of the expected response type to the response channel. Completion of service method implementations will automatically close response channels in order to prevent abandoned rpcs. \n\nCalls to `responseChannel.send()` will suspend until the corresponding client signals it is ready by requesting a message. Error responses can be returned to clients by either throwing an exception or invoking close on `responseChannel` with the desired exception. \n\nFor an example of how to implement long lived response streams please reference [MultipleClientSubscriptionsExample.kt](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/src/main/kotlin/krotoplus/example/MultipleClientSubscriptionsExample.kt). \n```kotlin\noverride suspend fun sayHelloServerStreaming(\n    request: HelloRequest,\n    responseChannel: SendChannel\u003cHelloReply\u003e\n) {        \n    for(char in request.name) {\n        responseChannel.send {\n            message = \"Hello $char!\"\n        }\n    }\n}\n\n``` \n\n#### Bi-Directional Streaming\n**_Client_**: `requestChannel.send()` will suspend until the corresponding server signals it is ready by requesting a message. In the event of a cancellation or the server responds with an error, both `requestChannel.send()` and `response.await()`, will throw the appropriate `StatusRuntimeException`. \n```kotlin\nval (requestChannel, responseChannel) = stub.sayHelloStreaming()\n\nlaunchProducerJob(requestChannel){\n    repeat(5){\n        send { name = \"person #$it\" }\n    }\n}\n\nresponseChannel.consumeEach {\n    println(\"Bidi Response: $it\")\n}\n``` \n**_Server_**: Bidi streaming rpc methods can respond to client requests by submitting messages of the expected response type to the response channel. Completion of service method implementations will automatically close response channels in order to prevent abandoned rpcs. \n\nCalls to `responseChannel.send()` will suspend until the corresponding client signals it is ready by requesting a message. Error responses can be returned to clients by either throwing an exception or invoking close on `responseChannel` with the desired exception. \n\nFor an example of how to implement long lived response streams please reference [MultipleClientSubscriptionsExample.kt](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/src/main/kotlin/krotoplus/example/MultipleClientSubscriptionsExample.kt). \n```kotlin\noverride suspend fun sayHelloStreaming(\n    requestChannel: ReceiveChannel\u003cHelloRequest\u003e,\n    responseChannel: SendChannel\u003cHelloReply\u003e\n) {\n    requestChannel.mapTo(responseChannel){\n    \n        HelloReply {\n            message = \"Hello there, ${it.name}!\"\n        }\n    }\n}\n```\n\n---\n### gRPC Stub Extensions\n#### [Configuration Options](https://github.com/marcoferrer/kroto-plus/blob/master/docs/markdown/kroto-plus-config.md#grpcstubextsgenoptions)\n\nThis modules generates convenience extensions that overload the request message argument for rpc methods with a builder lambda block and a default value. It also supports generating overloads based off [(google.api.method_signature)](https://github.com/googleapis/api-common-protos/blob/2769b82d4993ccbe66a3d886aa5466fdbd050ea2/google/api/client.proto#L79) method options. More info available [here](#method-signature-options-support)\n\n```kotlin\n               \n    //Kroto+ Generated Extension\n    val response = serviceStub.myRpcMethod {\n         id = 100\n         name = \"some name\"\n    }\n\n    //Original Java Fluent builders\n    val response = serviceStub.myRpcMethod(ExampleServiceGrpc.MyRpcMethodRequest\n        .newBuilder()\n        .setId(100)\n        .setName(\"some name\")\n        .build())                  \n```\n\nFor unary rpc methods, the generator will create the following extensions\n```kotlin\n    //Future Stub with default argument\n    fun ServiceBlockingStub.myRpcMethod(request: Request = Request.defaultInstance): ListenableFuture\u003cResponse\u003e\n    \n    //Future Stub with builder lambda \n    inline fun ServiceFutureStub.myRpcMethod(block: Request.Builder.() -\u003e Unit): ListenableFuture\u003cResponse\u003e\n        \n    //Blocking Stub with default argument\n    fun ServiceBlockingStub.myRpcMethod(request: Request = Request.defaultInstance): Response\n    \n    //Blocking Stub with builder lambda\n    inline fun ServiceBlockingStub.myRpcMethod(block: Request.Builder.() -\u003e Unit): Response \n``` \n\n#### Coroutine Support\nIn addition to request message arguments as builder lambda rpc overloads, coroutine overloads for rpc calls can also be generated.\nThis provides the same functionality as the generated coroutine stubs. Usage is identical to the client examples outlined in [Coroutine Client Examples](https://github.com/marcoferrer/kroto-plus#examples).\n \n* This is accomplished by defining extension functions for async service stubs.\n* This option requires the artifact ```kroto-plus-coroutines``` as a dependency.\n* If using rpc interceptors or other code that relies on ```io.grpc.Context``` then you need to be sure to add a ```GrpcContextElement``` to your ```CoroutineContext``` when launching a coroutine.\nChild coroutines will inherit this ```ThreadContextElement``` and the dispatcher will ensure that your grpc context is present on the executing thread.   \n\n```kotlin\n\n    Context.current().withValue(MY_KEY, myValue).attach()\n    \n    val myGrpcContext = Context.current()\n    \n    val job = launch( GrpcContextElement() ) { //Alternate usage:  myGrpcContext.asContextElement() \n       \n        launch {\n            assertEquals(myGrpcContext, Context.current())\n        }\n       \n        GlobalScope.launch{\n            assertNotEquals(myGrpcContext, Context.current())\n        } \n    }\n```\n \n---\n### Mock Service Generator\n#### [Configuration Options](https://github.com/marcoferrer/kroto-plus/blob/master/docs/markdown/kroto-plus-config.md#mockservicesgenoptions)\n\nThis generator creates mock implementations of proto service definitions. This is useful for orchestrating a set of expected responses, aiding in unit testing methods that rely on rpc calls.\n[Full example for mocking services in unit tests](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/src/test/kotlin/krotoplus/example/MockServiceResponseQueueTest.kt). The code generated relies on the ``` kroto-plus-test ``` artifact as a dependency. It is a small library that provides utility methods used by the mock services. \n* If no responses are added to the response queue then the mock service will return the default instance of the response type.\n* Currently only unary methods are being mocked, with support for other method types on the way \n ```kotlin\n@Test fun `Test Unary Response Queue`(){\n     \n     MockStandService.getStandByNameResponseQueue.apply {\n        //Queue up a valid response message\n        addMessage {\n            name = \"Star Platinum\"\n            powerLevel = 500\n            speed = 550\n            addAttacks {\n                name = \"ORA ORA ORA\"\n                damage = 100\n                range = StandProto.Attack.Range.CLOSE\n            }\n        }   \n           \n        //Queue up an error\n        addError(Status.INVALID_ARGUMENT)\n    }\n    \n    val standStub = StandServiceGrpc.newBlockingStub(grpcServerRule.channel)\n    \n    standStub.getStandByName { name = \"Star Platinum\" }.let{ response -\u003e\n        assertEquals(\"Star Platinum\",response.name)\n        assertEquals(500,response.powerLevel)\n        assertEquals(550,response.speed)\n        response.attacksList.first().let{ attack -\u003e\n            assertEquals(\"ORA ORA ORA\",attack.name)\n            assertEquals(100,attack.damage)\n            assertEquals(StandProto.Attack.Range.CLOSE,attack.range)\n        }\n    }\n    \n    try{\n        standStub.getStandByName { name = \"The World\" }\n        fail(\"Exception was expected with status code: ${Status.INVALID_ARGUMENT.code}\")\n    }catch (e: StatusRuntimeException){\n        assertEquals(Status.INVALID_ARGUMENT.code, e.status.code)\n    }\n}\n```\n---\n### Extendable Messages Generator ___(Experimental)___\n#### [Configuration Options](https://github.com/marcoferrer/kroto-plus/blob/master/docs/markdown/kroto-plus-config.md#krotoplus.compiler.ExtenableMessagesGenOptions)\nGenerated code relies on the ```kroto-plus-message``` artifact. This generator adds tagging interfaces to the java classes produce by protoc.\nIt also adds pseudo companion objects to provide a way to access proto message APIs in a non static manner.\nThe following is a small example of how to write generic methods and extensions that resolve both message and builders type.\n  \n```kotlin\ninline fun \u003creified M, B\u003e M.copy( block: B.() -\u003e Unit ): M\n        where M : KpMessage\u003cM, B\u003e, B : KpBuilder\u003cM\u003e {\n    return this.toBuilder.apply(block).build()\n}\n\n// Usage\nmyMessage.copy { ... }\n\ninline fun \u003creified M, B\u003e build( block: B.() -\u003e Unit ): M\n        where M : KpMessage\u003cM, B\u003e, B : KpBuilder\u003cM\u003e {\n\n    return KpCompanion.Registry[M::class.java].build(block)\n}\n\n// Usage\nbuild\u003cMyMessage\u003e { ... }\n\ninline fun \u003cM, B\u003e KpCompanion\u003cM, B\u003e.build( block: B.() -\u003e Unit ): M\n        where B : KpBuilder\u003cM\u003e,M : KpMessage\u003cM,B\u003e {\n\n    return newBuilder().apply(block).build()\n}\n\n// Usage\nMyMessage.Companion.build { ... }\n\n```\n---\n### User Defined Generator Scripts\nUsers can define kotlin scripts that they would like to run during code generation.\nFor type completion, scripts can be couple with a small gradle build script, although this is completely optional.\nSamples are available in the [kp-script](https://github.com/marcoferrer/kroto-plus/tree/master/example-project/kp-scripts) directory of the example project.\n\nThere are two categories of scripts available. \n* #### **[Insertion Scripts](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/kp-scripts/src/main/kotlin/sampleInsertionScript.kts)**\n  * [Configuration Options](https://github.com/marcoferrer/kroto-plus/blob/master/docs/markdown/kroto-plus-config.md#insertionsgenoptions)\n  * Using the insertion api from the java protoc plugin, users can add code at specific points in generated java classes.\n  * This is useful for adding code to allow more idiomatic use of generated java classes from Kotlin.\n  * The entire ```ExtendableMessages``` generator can be implemented using an insertion script, an example can be in the example script [extendableMessages.kts](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/kp-scripts/src/main/kotlin/extendableMessages.kts).   \n  * Additional information regarding the insertion api can be found in the [official docs](https://developers.google.com/protocol-buffers/docs/reference/java-generated#plugins)\n* #### **[Generator Scripts](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/kp-scripts/src/main/kotlin/helloThere.kts)**\n  * [Configuration Options](https://github.com/marcoferrer/kroto-plus/blob/master/docs/markdown/kroto-plus-config.md#generatorscriptsgenoptions)\n  * These scripts implement the ```Generator``` interface used by all internal kroto+ code generators.\n  * Generators rely on the ```GeneratorContext```, which is available via the property ```context```. \n  * The ```context``` is used for iterating over files, messages, and services submitted by protoc.\n  * Example usage can be found in the [kp-script](https://github.com/marcoferrer/kroto-plus/blob/master/example-project/kp-scripts/src/main/kotlin/helloThere.kts) directory of the example project, as well as inside the ```generators``` [package](https://github.com/marcoferrer/kroto-plus/tree/master/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators) of the ```protoc-gen-kroto-plus``` artifact.\n\n#### Community Scripts\nCommunity contributions for scripts are welcomed and more information regarding guidelines will be published soon.  \n\n---\n\n#### Method Signature Options Support  \nUsage of [(google.api.method_signature)](https://github.com/googleapis/api-common-protos/blob/2769b82d4993ccbe66a3d886aa5466fdbd050ea2/google/api/client.proto#L79) method option is now supported.\nThis allows users to customize the method parameters outputted in generated clients as well as stub extensions.\nTo config your rpc methods, first add the google common proto dependency to your build\n```groovy\ndependencies{\n    compileOnly \"com.google.api.grpc:proto-google-common-protos:1.16.0\"\n}\n```\n\nThen add the following import to your proto definition.\n```proto\nimport \"google/api/client.proto\";\n```    \n\nNow the method option should be available for usage in your method definition\n```proto\n// Sends a greeting\nrpc SayHello (HelloRequest) returns (HelloReply){\n    option (google.api.method_signature) = \"name\";\n};\n```\n\nThis will result in the following method signature being outputed from gRPC and stub extension code generators.\n```kotlin\n fun GreeterStub.sayHello(name: String): HelloReply{\n    val request = HelloRequest.newBuilder()\n        .setName(name)\n        .build()\n    return sayHello(request)\n }\n```\n\n---\n\n## Getting Started With Gradle\n\n#### Repositories\n* Available on ```jcenter()``` or ```mavenCentral()```\n* SNAPSHOT\n```groovy\nrepositories {\n    maven { url 'https://oss.jfrog.org/artifactory/oss-snapshot-local' }\n}\n```\n* Bintray\n```groovy\n// Useful when syncronization to jcenter or maven central are taking longer than expected\nrepositories {\n    maven { url 'https://dl.bintray.com/marcoferrer/kroto-plus/' }\n}\n```\n\n##### Configuring Protobuf Gradle Plugin\n```groovy\nplugins{\n    id 'com.google.protobuf' version '0.8.6'\n}\n\nprotobuf {\n    protoc { artifact = \"com.google.protobuf:protoc:$protobufVersion\"}\n\n    plugins {\n        kroto {\n            artifact = \"com.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:$krotoPlusVersion\"\n        }\n    }\n\n    generateProtoTasks {\n        def krotoConfig = file(\"krotoPlusConfig.asciipb\") // Or .json\n\n        all().each{ task -\u003e\n            // Adding the config file to the task inputs lets UP-TO-DATE checks\n            // include changes to configuration\n            task.inputs.files krotoConfig\n\n            task.plugins {\n                kroto {\n                    outputSubDir = \"java\"\n                    option \"ConfigPath=$krotoConfig\"\n                }\n            }\n        }\n    }\n}\n```\n---\n## Getting Started With Maven\n\n#### Repositories\n* Available on ```jcenter``` or ```mavenCentral```\n* SNAPSHOT\n```xml\n\u003crepository\u003e\n    \u003cid\u003eoss-snapshot\u003c/id\u003e\n    \u003cname\u003eOSS Snapshot Repository\u003c/name\u003e\n    \u003curl\u003ehttps://oss.jfrog.org/artifactory/oss-snapshot-local\u003c/url\u003e\n    \u003csnapshots\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n    \u003c/snapshots\u003e\n\u003c/repository\u003e\n```\n* Bintray\n```xml\n\u003c!-- Useful when syncronization to jcenter or maven central are taking longer than expected--\u003e\n\u003crepository\u003e\n    \u003cid\u003ekroto-plus-bintray\u003c/id\u003e\n    \u003cname\u003eKroto Plus Bintray Repository\u003c/name\u003e\n    \u003curl\u003ehttps://dl.bintray.com/marcoferrer/kroto-plus/\u003c/url\u003e\n\u003c/repository\u003e\n```\n\n##### Configuring Protobuf Maven Plugin\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.xolstice.maven.plugins\u003c/groupId\u003e\n    \u003cartifactId\u003eprotobuf-maven-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e0.6.1\u003c/version\u003e\n    \u003cconfiguration\u003e\n        \u003cprotocArtifact\u003ecom.google.protobuf:protoc:3.6.1:exe:${os.detected.classifier}\u003c/protocArtifact\u003e\n    \u003c/configuration\u003e\n    \u003cexecutions\u003e\n        \u003cexecution\u003e\n            \u003cgoals\u003e\u003cgoal\u003ecompile\u003c/goal\u003e\u003c/goals\u003e\n        \u003c/execution\u003e\n        \u003cexecution\u003e\n            \u003cid\u003egrpc-java\u003c/id\u003e\n            \u003cgoals\u003e\u003cgoal\u003ecompile-custom\u003c/goal\u003e\u003c/goals\u003e\n            \u003cconfiguration\u003e\n                \u003cpluginId\u003egrpc-java\u003c/pluginId\u003e\n                \u003cpluginArtifact\u003eio.grpc:protoc-gen-grpc-java:1.17.1:exe:${os.detected.classifier}\u003c/pluginArtifact\u003e\n            \u003c/configuration\u003e\n        \u003c/execution\u003e\n        \u003cexecution\u003e\n            \u003cid\u003ekroto-plus\u003c/id\u003e\n            \u003cgoals\u003e\n                \u003cgoal\u003ecompile-custom\u003c/goal\u003e\n            \u003c/goals\u003e\n            \u003cconfiguration\u003e\n                \u003cpluginId\u003ekroto-plus\u003c/pluginId\u003e\n                \u003cpluginArtifact\u003ecom.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:${krotoPlusVersion}:exe:${os.detected.classifier}\u003c/pluginArtifact\u003e\n                \u003cpluginParameter\u003eConfigPath=${project.basedir}/krotoPlusConfig.asciipb\u003c/pluginParameter\u003e\n            \u003c/configuration\u003e\n        \u003c/execution\u003e\n    \u003c/executions\u003e\n\u003c/plugin\u003e\n\n```\nAdd generated sources to Kotlin plugin\n```xml\n\u003cplugin\u003e\n    \u003cartifactId\u003ekotlin-maven-plugin\u003c/artifactId\u003e\n    \u003cgroupId\u003eorg.jetbrains.kotlin\u003c/groupId\u003e\n    \u003cversion\u003e${kotlin.version}\u003c/version\u003e\n    \u003cexecutions\u003e\n        \u003cexecution\u003e\n            \u003cid\u003ecompile\u003c/id\u003e\n            \u003cgoals\u003e\n                \u003cgoal\u003ecompile\u003c/goal\u003e\n            \u003c/goals\u003e\n            \u003cconfiguration\u003e\n                \u003csourceDirs\u003e\n                    \u003csourceDir\u003e${project.basedir}/target/generated-sources/protobuf/kroto-plus\u003c/sourceDir\u003e\n                \u003c/sourceDirs\u003e\n            \u003c/configuration\u003e\n        \u003c/execution\u003e\n    \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\n## Configuring Generators\n* [Documentation \u0026 Usage Examples](https://kroto-plus.readme.io/docs/configuration-file)\n\n#### Credit\nThis project relies on [Kotlin Poet](https://github.com/square/kotlinpoet) for building Kotlin sources. A big thanks to all of its contributors. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcoferrer%2Fkroto-plus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcoferrer%2Fkroto-plus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcoferrer%2Fkroto-plus/lists"}