From 0f3b446413f3391f73d14c46888a59a58baf0ddd Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Wed, 10 Nov 2021 01:13:31 +0100 Subject: [PATCH] Add service-td --- .gitignore | 4 + pom.xml | 39 ++++ {volvox => service-td}/.dockerignore | 0 {volvox => service-td}/.gitignore | 3 - {volvox => service-td}/README.md | 35 +--- {volvox => service-td}/pom.xml | 102 +++++----- .../src/main/docker/Dockerfile.jvm | 6 +- .../src/main/docker/Dockerfile.legacy-jar | 6 +- .../src/main/docker/Dockerfile.native | 4 +- .../main/docker/Dockerfile.native-distroless | 4 +- .../main/java/io/volvox/td/BufferUtils.java | 81 ++++++++ .../java/io/volvox/td/ExecutorProducer.java | 17 ++ .../main/java/io/volvox/td/RandomUUID.java | 13 ++ .../src/main/java/io/volvox/td/TdClient.java | 16 ++ .../java/io/volvox/td/TdClientProducers.java | 38 ++++ .../main/java/io/volvox/td/TdException.java | 25 +++ .../java/io/volvox/td/TdNativeClient.java | 86 +++++++++ .../src/main/java/io/volvox/td/TdObject.java | 17 ++ .../main/java/io/volvox/td/TdObjectCodec.java | 36 ++++ .../main/java/io/volvox/td/TdResource.java | 33 ++++ .../src/main/java/io/volvox/td/TdService.java | 43 +++++ .../src/main/java/io/volvox/td/TdSession.java | 84 ++++++++ .../java/io/volvox/td/TdSessionRegistry.java | 28 +++ .../resources/META-INF/resources/index.html | 175 +++++++++++++++++ .../src/main/resources/application.properties | 1 + .../java/io/volvox/td/NativeTdResourceIT.java | 9 + .../java/io/volvox/td/TdResourceTest.java | 21 ++ .../it/cavallium/ExampleDelayedResource.java | 25 --- .../java/it/cavallium/ExampleResource.java | 16 -- .../java/it/cavallium/GreetingConfig.java | 12 -- .../resources/META-INF/resources/index.html | 180 ------------------ volvox/src/main/resources/application.yml | 2 - .../cavallium/ExampleDelayResourceTest.java | 22 --- .../it/cavallium/ExampleResourceTest.java | 17 -- .../it/cavallium/NativeExampleResourceIT.java | 9 - 35 files changed, 835 insertions(+), 374 deletions(-) create mode 100644 pom.xml rename {volvox => service-td}/.dockerignore (100%) rename {volvox => service-td}/.gitignore (93%) rename {volvox => service-td}/README.md (57%) rename {volvox => service-td}/pom.xml (78%) rename {volvox => service-td}/src/main/docker/Dockerfile.jvm (92%) rename {volvox => service-td}/src/main/docker/Dockerfile.legacy-jar (93%) rename {volvox => service-td}/src/main/docker/Dockerfile.native (81%) rename {volvox => service-td}/src/main/docker/Dockerfile.native-distroless (86%) create mode 100644 service-td/src/main/java/io/volvox/td/BufferUtils.java create mode 100644 service-td/src/main/java/io/volvox/td/ExecutorProducer.java create mode 100644 service-td/src/main/java/io/volvox/td/RandomUUID.java create mode 100644 service-td/src/main/java/io/volvox/td/TdClient.java create mode 100644 service-td/src/main/java/io/volvox/td/TdClientProducers.java create mode 100644 service-td/src/main/java/io/volvox/td/TdException.java create mode 100644 service-td/src/main/java/io/volvox/td/TdNativeClient.java create mode 100644 service-td/src/main/java/io/volvox/td/TdObject.java create mode 100644 service-td/src/main/java/io/volvox/td/TdObjectCodec.java create mode 100644 service-td/src/main/java/io/volvox/td/TdResource.java create mode 100644 service-td/src/main/java/io/volvox/td/TdService.java create mode 100644 service-td/src/main/java/io/volvox/td/TdSession.java create mode 100644 service-td/src/main/java/io/volvox/td/TdSessionRegistry.java create mode 100644 service-td/src/main/resources/META-INF/resources/index.html create mode 100644 service-td/src/main/resources/application.properties create mode 100644 service-td/src/test/java/io/volvox/td/NativeTdResourceIT.java create mode 100644 service-td/src/test/java/io/volvox/td/TdResourceTest.java delete mode 100644 volvox/src/main/java/it/cavallium/ExampleDelayedResource.java delete mode 100644 volvox/src/main/java/it/cavallium/ExampleResource.java delete mode 100644 volvox/src/main/java/it/cavallium/GreetingConfig.java delete mode 100644 volvox/src/main/resources/META-INF/resources/index.html delete mode 100644 volvox/src/main/resources/application.yml delete mode 100644 volvox/src/test/java/it/cavallium/ExampleDelayResourceTest.java delete mode 100644 volvox/src/test/java/it/cavallium/ExampleResourceTest.java delete mode 100644 volvox/src/test/java/it/cavallium/NativeExampleResourceIT.java diff --git a/.gitignore b/.gitignore index 3ff5718..66506ce 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,7 @@ modules.xml # End of https://www.gitignore.io/api/intellij+all /example/ +**/.cache/ +**/mvnw +**/mvnw.cmd +**/.mvn diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..024cc67 --- /dev/null +++ b/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + it.volvox + volvox-parent-root + 2.0 + pom + Volvox project root + + + + + + maven-assembly-plugin + 3.3.0 + + quarkus-volvox + true + true + false + + assembly.xml + assembly-complete.xml + + dist + + + + + + + complete + + service-td + + + + diff --git a/volvox/.dockerignore b/service-td/.dockerignore similarity index 100% rename from volvox/.dockerignore rename to service-td/.dockerignore diff --git a/volvox/.gitignore b/service-td/.gitignore similarity index 93% rename from volvox/.gitignore rename to service-td/.gitignore index 9614c54..bdf57ce 100644 --- a/volvox/.gitignore +++ b/service-td/.gitignore @@ -37,6 +37,3 @@ nb-configuration.xml # Local environment .env -/.mvn/ -/mvnw -/mvnw.cmd diff --git a/volvox/README.md b/service-td/README.md similarity index 57% rename from volvox/README.md rename to service-td/README.md index ab80a78..fc22b4b 100644 --- a/volvox/README.md +++ b/service-td/README.md @@ -1,13 +1,12 @@ -# Volvox Project +# service-td Project This project uses Quarkus, the Supersonic Subatomic Java Framework. -If you want to learn more about Quarkus, please visit its website: [quarkus.io](https://quarkus.io/). +If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . ## Running the application in dev mode You can run your application in dev mode that enables live coding using: - ```shell script ./mvnw compile quarkus:dev ``` @@ -17,18 +16,15 @@ You can run your application in dev mode that enables live coding using: ## Packaging and running the application The application can be packaged using: - ```shell script ./mvnw package ``` - -It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. Be aware that it’s not an _über-jar_ as -the dependencies are copied into the `target/quarkus-app/lib/` directory. +It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. +Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. If you want to build an _über-jar_, execute the following command: - ```shell script ./mvnw package -Dquarkus.package.type=uber-jar ``` @@ -37,40 +33,25 @@ The application, packaged as an _über-jar_, is now runnable using `java -jar ta ## Creating a native executable -You can create a native executable using: - +You can create a native executable using: ```shell script ./mvnw package -Pnative ``` -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - +Or, if you don't have GraalVM installed, you can run the native executable build in a container using: ```shell script ./mvnw package -Pnative -Dquarkus.native.container-build=true ``` -You can then execute your native executable with: `./target/volvox-1.0-SNAPSHOT-runner` +You can then execute your native executable with: `./target/service-td-1.0.0-SNAPSHOT-runner` -If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html -. +If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html. ## Related Guides -- RESTEasy Reactive ([guide](https://quarkus.io/guides/resteasy-reactive)): Reactive implementation of JAX-RS with - additional features. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions - that depend on it. -- YAML Configuration ([guide](https://quarkus.io/guides/config#yaml)): Use YAML to configure your Quarkus application ## Provided Code -### YAML Config - -Configure your application with YAML - -[Related guide section...](https://quarkus.io/guides/config-reference#configuration-examples) - -The Quarkus application configuration is located in `src/main/resources/application.yml`. - ### RESTEasy Reactive Easily start your Reactive RESTful Web Services diff --git a/volvox/pom.xml b/service-td/pom.xml similarity index 78% rename from volvox/pom.xml rename to service-td/pom.xml index 6d4f365..a0e1310 100644 --- a/volvox/pom.xml +++ b/service-td/pom.xml @@ -1,11 +1,10 @@ - + 4.0.0 - it.cavallium - volvox - 1.0-SNAPSHOT + it.volvox.service-td + service-td + 1.0.0-SNAPSHOT 3.8.1 true @@ -17,7 +16,16 @@ io.quarkus.platform 2.4.1.Final 3.0.0-M5 + 2.7.9.2 + 4.0.183 + + + mchv + MCHV Apache Maven Packages + https://mvn.mchv.eu/repository/mchv/ + + @@ -27,65 +35,48 @@ pom import + + it.tdlight + tdlight-java + ${volvox.tdlight.version} + + + it.tdlight + tdlight-natives-linux-amd64 + ${volvox.tdlight.natives.version} + - - io.quarkus - quarkus-resteasy-reactive-jackson - - - io.quarkus - quarkus-mutiny - - - io.quarkus - quarkus-hibernate-reactive - - - io.quarkus - quarkus-resteasy-reactive - - - io.quarkus - quarkus-config-yaml - - - io.quarkus - quarkus-elasticsearch-rest-client - - - io.quarkus - quarkus-smallrye-metrics - - - io.quarkus - quarkus-resteasy-reactive-jsonb - - - io.quarkus - quarkus-smallrye-reactive-messaging - - - io.quarkus - quarkus-elasticsearch-rest-high-level-client - - - io.quarkus - quarkus-hibernate-search-orm-elasticsearch - io.quarkus quarkus-reactive-pg-client io.quarkus - quarkus-reactive-routes + quarkus-smallrye-openapi + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-hibernate-reactive-panache + + + io.quarkus + quarkus-hibernate-validator io.quarkus quarkus-arc + + io.quarkus + quarkus-resteasy-reactive + + io.quarkus quarkus-junit5 @@ -96,6 +87,15 @@ rest-assured test + + + it.tdlight + tdlight-java + + + it.tdlight + tdlight-natives-linux-amd64 + diff --git a/volvox/src/main/docker/Dockerfile.jvm b/service-td/src/main/docker/Dockerfile.jvm similarity index 92% rename from volvox/src/main/docker/Dockerfile.jvm rename to service-td/src/main/docker/Dockerfile.jvm index 1c7c848..d2d6fc6 100644 --- a/volvox/src/main/docker/Dockerfile.jvm +++ b/service-td/src/main/docker/Dockerfile.jvm @@ -7,18 +7,18 @@ # # Then, build the image with: # -# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/volvox-jvm . +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/service-td-jvm . # # Then run the container using: # -# docker run -i --rm -p 8080:8080 quarkus/volvox-jvm +# docker run -i --rm -p 8080:8080 quarkus/service-td-jvm # # If you want to include the debug port into your docker image # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 # # Then run the container using : # -# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/volvox-jvm +# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/service-td-jvm # ### FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 diff --git a/volvox/src/main/docker/Dockerfile.legacy-jar b/service-td/src/main/docker/Dockerfile.legacy-jar similarity index 93% rename from volvox/src/main/docker/Dockerfile.legacy-jar rename to service-td/src/main/docker/Dockerfile.legacy-jar index 5a5a0ce..40b2a9e 100644 --- a/volvox/src/main/docker/Dockerfile.legacy-jar +++ b/service-td/src/main/docker/Dockerfile.legacy-jar @@ -7,18 +7,18 @@ # # Then, build the image with: # -# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/volvox-legacy-jar . +# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/service-td-legacy-jar . # # Then run the container using: # -# docker run -i --rm -p 8080:8080 quarkus/volvox-legacy-jar +# docker run -i --rm -p 8080:8080 quarkus/service-td-legacy-jar # # If you want to include the debug port into your docker image # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 # # Then run the container using : # -# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/volvox-legacy-jar +# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/service-td-legacy-jar # ### FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 diff --git a/volvox/src/main/docker/Dockerfile.native b/service-td/src/main/docker/Dockerfile.native similarity index 81% rename from volvox/src/main/docker/Dockerfile.native rename to service-td/src/main/docker/Dockerfile.native index a55c33d..e82479c 100644 --- a/volvox/src/main/docker/Dockerfile.native +++ b/service-td/src/main/docker/Dockerfile.native @@ -7,11 +7,11 @@ # # Then, build the image with: # -# docker build -f src/main/docker/Dockerfile.native -t quarkus/volvox . +# docker build -f src/main/docker/Dockerfile.native -t quarkus/service-td . # # Then run the container using: # -# docker run -i --rm -p 8080:8080 quarkus/volvox +# docker run -i --rm -p 8080:8080 quarkus/service-td # ### FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 diff --git a/volvox/src/main/docker/Dockerfile.native-distroless b/service-td/src/main/docker/Dockerfile.native-distroless similarity index 86% rename from volvox/src/main/docker/Dockerfile.native-distroless rename to service-td/src/main/docker/Dockerfile.native-distroless index 020f67f..cf219cc 100644 --- a/volvox/src/main/docker/Dockerfile.native-distroless +++ b/service-td/src/main/docker/Dockerfile.native-distroless @@ -7,11 +7,11 @@ # # Then, build the image with: # -# docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/volvox . +# docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/service-td . # # Then run the container using: # -# docker run -i --rm -p 8080:8080 quarkus/volvox +# docker run -i --rm -p 8080:8080 quarkus/service-td # ### FROM quay.io/quarkus/quarkus-distroless-image:1.0 diff --git a/service-td/src/main/java/io/volvox/td/BufferUtils.java b/service-td/src/main/java/io/volvox/td/BufferUtils.java new file mode 100644 index 0000000..654b87e --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/BufferUtils.java @@ -0,0 +1,81 @@ +package io.volvox.td; + +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferImpl; +import java.io.IOException; + +public class BufferUtils { + + private static final int CHUNK_SIZE = 8192; + + public static void writeBuf(ByteBufOutputStream os, Buffer dataToWrite) throws IOException { + var len = dataToWrite.length(); + os.writeInt(len); + byte[] part = new byte[CHUNK_SIZE]; + for (int i = 0; i < len; i += CHUNK_SIZE) { + var end = Math.min(i + CHUNK_SIZE, len); + dataToWrite.getBytes(i, end, part, 0); + os.write(part, 0, end - i); + } + } + + public static Buffer readBuf(ByteBufInputStream is) throws IOException { + int len = is.readInt(); + Buffer buf = Buffer.buffer(len); + byte[] part = new byte[1024]; + int readPart = 0; + for (int i = 0; i < len; i += 1024) { + var lenx = (Math.min(i + 1024, len)) - i; + if (lenx > 0) { + readPart = is.readNBytes(part, 0, lenx); + buf.appendBytes(part, 0, readPart); + } + } + return buf; + } + + public static io.vertx.core.buffer.Buffer rxReadBuf(ByteBufInputStream is) throws IOException { + int len = is.readInt(); + io.vertx.core.buffer.Buffer buf = io.vertx.core.buffer.Buffer.buffer(len); + byte[] part = new byte[1024]; + int readPart = 0; + for (int i = 0; i < len; i += 1024) { + var lenx = (Math.min(i + 1024, len)) - i; + if (lenx > 0) { + readPart = is.readNBytes(part, 0, lenx); + buf.appendBytes(part, 0, readPart); + } + } + return buf; + } + + public interface Writer { + + void write(ByteBufOutputStream os) throws IOException; + } + + public interface Reader { + + T read(ByteBufInputStream is) throws IOException; + } + + public static void encode(Buffer buffer, Writer writer) { + try (var os = new ByteBufOutputStream(((BufferImpl) buffer).byteBuf())) { + writer.write(os); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + + public static T decode(int pos, Buffer buffer, Reader reader) { + try (var is = new ByteBufInputStream(buffer.slice(pos, buffer.length()).getByteBuf())) { + return reader.read(is); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/service-td/src/main/java/io/volvox/td/ExecutorProducer.java b/service-td/src/main/java/io/volvox/td/ExecutorProducer.java new file mode 100644 index 0000000..432c0f9 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/ExecutorProducer.java @@ -0,0 +1,17 @@ +package io.volvox.td; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Singleton; + +@ApplicationScoped +public class ExecutorProducer { + + @Produces + @Singleton + public Executor produceExecutor() { + return Executors.newCachedThreadPool(); + } +} diff --git a/service-td/src/main/java/io/volvox/td/RandomUUID.java b/service-td/src/main/java/io/volvox/td/RandomUUID.java new file mode 100644 index 0000000..2b04ece --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/RandomUUID.java @@ -0,0 +1,13 @@ +package io.volvox.td; + +import java.util.UUID; + +public class RandomUUID { + + final String uuid; + + public RandomUUID() { + this.uuid = UUID.randomUUID().toString(); + } + +} diff --git a/service-td/src/main/java/io/volvox/td/TdClient.java b/service-td/src/main/java/io/volvox/td/TdClient.java new file mode 100644 index 0000000..ee0fbf8 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdClient.java @@ -0,0 +1,16 @@ +package io.volvox.td; + +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import it.tdlight.jni.TdApi; +import it.tdlight.jni.TdApi.Update; + +public interface TdClient { + Multi updates(); + + Uni send(TdApi.Function function); + + Uni execute(TdApi.Function function); + + void dispose(); +} diff --git a/service-td/src/main/java/io/volvox/td/TdClientProducers.java b/service-td/src/main/java/io/volvox/td/TdClientProducers.java new file mode 100644 index 0000000..e85607b --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdClientProducers.java @@ -0,0 +1,38 @@ +package io.volvox.td; + +import io.quarkus.vertx.runtime.VertxProducer; +import it.tdlight.common.Init; +import it.tdlight.common.ReactiveTelegramClient; +import it.tdlight.common.utils.CantLoadLibrary; +import it.tdlight.tdlight.ClientManager; +import java.time.Duration; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Singleton; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jboss.logging.Logger; + +@ApplicationScoped +class TdClientProducers { + + private static final Logger LOGGER = Logger.getLogger(VertxProducer.class); + + @ConfigProperty(name = "td.requests.timeout") + Duration requestTimeout; + + @Produces + ReactiveTelegramClient produceReactiveTelegramClient() { + try { + Init.start(); + } catch (CantLoadLibrary e) { + LOGGER.error(e); + } + return ClientManager.createReactive(); + } + + @Produces + @Singleton + public Duration produceRequestTimeout() { + return requestTimeout; + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdException.java b/service-td/src/main/java/io/volvox/td/TdException.java new file mode 100644 index 0000000..0207a56 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdException.java @@ -0,0 +1,25 @@ +package io.volvox.td; + +public class TdException extends Exception { + + private final int code; + private final String message; + + public TdException(int code, String message) { + super(code + ": " + message); + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public String getErrorMessage() { + return message; + } + + @Override public String toString() { + return code + ": " + message; + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdNativeClient.java b/service-td/src/main/java/io/volvox/td/TdNativeClient.java new file mode 100644 index 0000000..501fd83 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdNativeClient.java @@ -0,0 +1,86 @@ +package io.volvox.td; + +import io.quarkus.runtime.StartupEvent; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import it.tdlight.common.ReactiveTelegramClient; +import it.tdlight.jni.TdApi; +import it.tdlight.jni.TdApi.Error; +import it.tdlight.jni.TdApi.Update; +import java.time.Duration; +import javax.annotation.PostConstruct; +import javax.enterprise.context.Dependent; +import javax.enterprise.event.Observes; +import javax.inject.Inject; + +@Dependent +public class TdNativeClient implements TdClient { + + @Inject + ReactiveTelegramClient client; + + @Inject + Duration requestTimeout; + + private Multi updates; + + @PostConstruct + void init() { + this.updates = Multi.createFrom().emitter(emitter -> { + client.createAndRegisterClient(); + client.setListener(signal -> { + if (signal.isClosed()) { + emitter.complete(); + } else if (signal.isUpdate()) { + var update = (TdApi.Update) signal.getUpdate(); + emitter.emit(update); + } else if (signal.isException()) { + emitter.fail(signal.getException()); + } else { + throw new IllegalStateException("Unknown signal: " + signal); + } + }); + emitter.onTermination(client::dispose); + }).broadcast().toAllSubscribers(); + } + + @Override public Multi updates() { + return updates; + } + + @Override @SuppressWarnings("unchecked") + public Uni send(TdApi.Function function) { + return (Uni) Uni + .createFrom() + .publisher(client.send(function, requestTimeout)) + .onItem() + .transformToUni(item -> { + if (item.getConstructor() == Error.CONSTRUCTOR) { + TdApi.Error error = (TdApi.Error) item; + return Uni.createFrom().failure(new TdException(error.code, error.message)); + } else { + return Uni.createFrom().item(item); + } + }); + } + + @Override @SuppressWarnings("unchecked") + public Uni execute(TdApi.Function function) { + return (Uni) Uni + .createFrom() + .item(() -> client.execute(function)) + .onItem() + .transformToUni(item -> { + if (item.getConstructor() == Error.CONSTRUCTOR) { + TdApi.Error error = (TdApi.Error) item; + return Uni.createFrom().failure(new TdException(error.code, error.message)); + } else { + return Uni.createFrom().item(item); + } + }); + } + + @Override public void dispose() { + this.client.dispose(); + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdObject.java b/service-td/src/main/java/io/volvox/td/TdObject.java new file mode 100644 index 0000000..0a7b280 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdObject.java @@ -0,0 +1,17 @@ +package io.volvox.td; + +import it.tdlight.jni.TdApi; + +public class TdObject { + + private final TdApi.Object object; + + public TdObject(TdApi.Object object) { + this.object = object; + } + + public T getObject() { + //noinspection unchecked + return (T) object; + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdObjectCodec.java b/service-td/src/main/java/io/volvox/td/TdObjectCodec.java new file mode 100644 index 0000000..4320328 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdObjectCodec.java @@ -0,0 +1,36 @@ +package io.volvox.td; + +import io.vertx.core.buffer.Buffer; +import io.vertx.core.eventbus.MessageCodec; +import it.tdlight.jni.TdApi; +import it.tdlight.jni.TdApi.Deserializer; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Singleton; + +@ApplicationScoped +public class TdObjectCodec implements MessageCodec { + + @Override public void encodeToWire(Buffer buffer, TdObject t) { + BufferUtils.encode(buffer, out -> t.getObject().serialize(out)); + } + + @Override + public TdObject decodeFromWire(int i, Buffer buffer) { + return new TdObject(BufferUtils.decode(i, buffer, Deserializer::deserialize)); + } + + @Override public TdObject transform(TdObject t) { + // If a message is sent *locally* across the event bus. + // This sends message just as is + return t; + } + + @Override public String name() { + return "TdObjectCodec"; + } + + @Override public byte systemCodecID() { + // Always "-1" + return -1; + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdResource.java b/service-td/src/main/java/io/volvox/td/TdResource.java new file mode 100644 index 0000000..79ff526 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdResource.java @@ -0,0 +1,33 @@ +package io.volvox.td; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/api/td") +public class TdResource { + + @Inject TdSessionRegistry tdSessionRegistry; + + @Inject TdService tdService; + + @Path("/list") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String listSessions() { + StringBuilder sb = new StringBuilder(); + for (var session : tdSessionRegistry.getSessions()) { + sb.append(session).append(System.lineSeparator()); + } + return sb.toString(); + } + + @Path("/create-session") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String createSession() { + return tdService.startSession(null); + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdService.java b/service-td/src/main/java/io/volvox/td/TdService.java new file mode 100644 index 0000000..76d2420 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdService.java @@ -0,0 +1,43 @@ +package io.volvox.td; + +import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.vertx.ConsumeEvent; +import io.vertx.core.eventbus.EventBus; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.Instance; +import javax.inject.Inject; + +@ApplicationScoped +public class TdService { + + private final ConcurrentMap clients = new ConcurrentHashMap<>(); + + @Inject + EventBus bus; + + @Inject + Instance sessionInstances; + + @ConsumeEvent(value = "td.start-session") + public String startSession(Void param) { + String uuid = generateRandomUUID(); + + var client = sessionInstances.get(); + clients.put(uuid, client); + client.publishUpdates(); + + return uuid; + } + + private String generateRandomUUID() { + return UUID.randomUUID().toString(); + } + + void shutdown(@Observes ShutdownEvent event) { + clients.forEach((uuid, client) -> client.dispose()); + } +} \ No newline at end of file diff --git a/service-td/src/main/java/io/volvox/td/TdSession.java b/service-td/src/main/java/io/volvox/td/TdSession.java new file mode 100644 index 0000000..7e80289 --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdSession.java @@ -0,0 +1,84 @@ +package io.volvox.td; + +import io.quarkus.vertx.ConsumeEvent; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import io.smallrye.mutiny.subscription.Cancellable; +import io.vertx.core.eventbus.DeliveryOptions; +import io.vertx.core.eventbus.EventBus; +import io.vertx.core.eventbus.Message; +import it.tdlight.jni.TdApi.Function; +import it.tdlight.jni.TdApi.Object; +import it.tdlight.jni.TdApi.Update; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +@Dependent +public class TdSession implements TdClient { + + private static final DeliveryOptions UPDATES_OPTS + = new DeliveryOptions().setCodecName("TdObjectCodec"); + private static final DeliveryOptions SEND_OPTS + = new DeliveryOptions().setCodecName("TdObjectCodec"); + + @Inject + RandomUUID uuid; + + @Inject + Executor executor; + + @Inject + TdNativeClient client; + + @Inject + EventBus bus; + + private final AtomicReference updatesPublisher = new AtomicReference<>(); + + @Override public Multi updates() { + return client.updates(); + } + + public void publishUpdates() { + var newPublisher = this.updates() + .runSubscriptionOn(executor) + .subscribe() + .with(item -> bus.publish("td.update", item, UPDATES_OPTS)); + var prev = this.updatesPublisher.getAndSet(newPublisher); + if (prev != null) { + throw new IllegalStateException("Called publishUpdates twice!"); + } + } + + @ConsumeEvent(value = "td.send", codec = TdObjectCodec.class) + void onSendRequest(Message msg) { + this.send(msg.body().getObject()).subscribe() + .with(message -> msg.reply(message, SEND_OPTS), + ex -> { + if (ex instanceof TdException tdException) { + msg.fail(tdException.getCode(), tdException.getMessage()); + } else { + msg.fail(500, ex.toString()); + } + } + ); + } + + @Override public Uni send(Function function) { + return client.send(function); + } + + @SuppressWarnings("unchecked") @Override public Uni execute(Function function) { + return null; + } + + @Override public void dispose() { + var updatesPublisher = this.updatesPublisher.get(); + if (updatesPublisher != null) { + updatesPublisher.cancel(); + } + client.dispose(); + } +} diff --git a/service-td/src/main/java/io/volvox/td/TdSessionRegistry.java b/service-td/src/main/java/io/volvox/td/TdSessionRegistry.java new file mode 100644 index 0000000..1ed09bd --- /dev/null +++ b/service-td/src/main/java/io/volvox/td/TdSessionRegistry.java @@ -0,0 +1,28 @@ +package io.volvox.td; + +import io.vertx.core.impl.ConcurrentHashSet; +import java.util.Set; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Disposes; +import javax.enterprise.inject.Produces; + +@ApplicationScoped +public class TdSessionRegistry { + + private final Set clients = new ConcurrentHashSet<>(); + + @Produces + public RandomUUID produceUUID() { + var randomUUID = new RandomUUID(); + clients.add(randomUUID.uuid); + return randomUUID; + } + + public void cleanUUID(@Disposes RandomUUID toClean) { + clients.remove(toClean.uuid); + } + + public Set getSessions() { + return clients; + } +} diff --git a/service-td/src/main/resources/META-INF/resources/index.html b/service-td/src/main/resources/META-INF/resources/index.html new file mode 100644 index 0000000..a59e08f --- /dev/null +++ b/service-td/src/main/resources/META-INF/resources/index.html @@ -0,0 +1,175 @@ + + + + + service-td - 1.0.0-SNAPSHOT + + + + + + +
+
+

Congratulations, you have created a new Quarkus cloud application.

+ +

What is this page?

+ +

This page is served by Quarkus. The source is in + src/main/resources/META-INF/resources/index.html.

+ +

What are your next steps?

+ +

If not already done, run the application in dev mode using: ./mvnw compile quarkus:dev. +

+
    +
  • Your static assets are located in src/main/resources/META-INF/resources.
  • +
  • Configure your application in src/main/resources/application.properties.
  • +
  • Quarkus now ships with a Dev UI (available in dev mode only)
  • +
  • Play with the provided code located in src/main/java:
  • +
+
+

RESTEasy Reactive

+

Easily start your Reactive RESTful Web Services

+

@Path: /api/td

+

Related guide section...

+
+ +
+
+
+

Application

+
    +
  • GroupId: it.volvox.service-td
  • +
  • ArtifactId: service-td
  • +
  • Version: 1.0.0-SNAPSHOT
  • +
  • Quarkus Version: 2.4.1.Final
  • +
+
+
+

Do you like Quarkus?

+
    +
  • Go give it a star on GitHub.
  • +
+
+
+

Selected extensions guides

+
    +
+
+ +
+
+ + \ No newline at end of file diff --git a/service-td/src/main/resources/application.properties b/service-td/src/main/resources/application.properties new file mode 100644 index 0000000..45fd8d3 --- /dev/null +++ b/service-td/src/main/resources/application.properties @@ -0,0 +1 @@ +td.requests.timeout = 10s diff --git a/service-td/src/test/java/io/volvox/td/NativeTdResourceIT.java b/service-td/src/test/java/io/volvox/td/NativeTdResourceIT.java new file mode 100644 index 0000000..7aebde7 --- /dev/null +++ b/service-td/src/test/java/io/volvox/td/NativeTdResourceIT.java @@ -0,0 +1,9 @@ +package io.volvox.td; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class NativeTdResourceIT extends TdResourceTest { + + // Execute the same tests but in native mode. +} \ No newline at end of file diff --git a/service-td/src/test/java/io/volvox/td/TdResourceTest.java b/service-td/src/test/java/io/volvox/td/TdResourceTest.java new file mode 100644 index 0000000..55bf2a6 --- /dev/null +++ b/service-td/src/test/java/io/volvox/td/TdResourceTest.java @@ -0,0 +1,21 @@ +package io.volvox.td; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +@QuarkusTest +public class TdResourceTest { + + @Test + public void testEmptyList() { + given() + .when().get("/api/td/list") + .then() + .statusCode(200) + .body(is("")); + } + +} \ No newline at end of file diff --git a/volvox/src/main/java/it/cavallium/ExampleDelayedResource.java b/volvox/src/main/java/it/cavallium/ExampleDelayedResource.java deleted file mode 100644 index 5545010..0000000 --- a/volvox/src/main/java/it/cavallium/ExampleDelayedResource.java +++ /dev/null @@ -1,25 +0,0 @@ -package it.cavallium; - -import io.smallrye.mutiny.Uni; -import java.time.Duration; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("/delay") -public class ExampleDelayedResource { - - @Path("{seconds:\\d+}") - @GET - @Produces(MediaType.TEXT_PLAIN) - public Uni delay(int seconds) { - return Uni - - // Create the response item - .createFrom().item("Hello from the future! %d seconds have passed".formatted(seconds)) - - // Delay the response by n seconds - .onItem().delayIt().by(Duration.ofSeconds(seconds)); - } -} \ No newline at end of file diff --git a/volvox/src/main/java/it/cavallium/ExampleResource.java b/volvox/src/main/java/it/cavallium/ExampleResource.java deleted file mode 100644 index 9845fad..0000000 --- a/volvox/src/main/java/it/cavallium/ExampleResource.java +++ /dev/null @@ -1,16 +0,0 @@ -package it.cavallium; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("/hello") -public class ExampleResource { - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - return "Hello RESTEasy Reactive"; - } -} \ No newline at end of file diff --git a/volvox/src/main/java/it/cavallium/GreetingConfig.java b/volvox/src/main/java/it/cavallium/GreetingConfig.java deleted file mode 100644 index 76f7416..0000000 --- a/volvox/src/main/java/it/cavallium/GreetingConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.cavallium; - -import io.smallrye.config.ConfigMapping; -import io.smallrye.config.WithName; - -@ConfigMapping(prefix = "greeting") -public interface GreetingConfig { - - @WithName("message") - String message(); - -} \ No newline at end of file diff --git a/volvox/src/main/resources/META-INF/resources/index.html b/volvox/src/main/resources/META-INF/resources/index.html deleted file mode 100644 index dd67f2b..0000000 --- a/volvox/src/main/resources/META-INF/resources/index.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - volvox - 1.0-SNAPSHOT - - - - - - -
-
-

Congratulations, you have created a new Quarkus cloud application.

- -

What is this page?

- -

This page is served by Quarkus. The source is in - src/main/resources/META-INF/resources/index.html.

- -

What are your next steps?

- -

If not already done, run the application in dev mode using: ./mvnw compile quarkus:dev. -

-
    -
  • Your static assets are located in src/main/resources/META-INF/resources.
  • -
  • Configure your application in src/main/resources/application.yml.
  • -
  • Quarkus now ships with a Dev UI (available in dev mode only)
  • -
  • Play with the provided code located in src/main/java:
  • -
-
-

RESTEasy Reactive

-

Easily start your Reactive RESTful Web Services

-

@Path: /hello

-

Related guide section...

-
- -
-
-
-

Application

-
    -
  • GroupId: it.cavallium
  • -
  • ArtifactId: volvox
  • -
  • Version: 1.0-SNAPSHOT
  • -
  • Quarkus Version: 2.4.1.Final
  • -
-
-
-

Do you like Quarkus?

-
    -
  • Go give it a star on GitHub.
  • -
-
-
-

Selected extensions guides

- -
- -
-
- - \ No newline at end of file diff --git a/volvox/src/main/resources/application.yml b/volvox/src/main/resources/application.yml deleted file mode 100644 index 527a35f..0000000 --- a/volvox/src/main/resources/application.yml +++ /dev/null @@ -1,2 +0,0 @@ -greeting: - message: "hello" diff --git a/volvox/src/test/java/it/cavallium/ExampleDelayResourceTest.java b/volvox/src/test/java/it/cavallium/ExampleDelayResourceTest.java deleted file mode 100644 index c27eedb..0000000 --- a/volvox/src/test/java/it/cavallium/ExampleDelayResourceTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package it.cavallium; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.is; - -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Test; - -@QuarkusTest -public class ExampleDelayResourceTest { - - @Test - public void testHelloEndpoint() { - given() - .when() - .get("/delay?duration=1") - .then() - .statusCode(200) - .body(is("Hello from the future! %d seconds have passed".formatted(1))); - } - -} \ No newline at end of file diff --git a/volvox/src/test/java/it/cavallium/ExampleResourceTest.java b/volvox/src/test/java/it/cavallium/ExampleResourceTest.java deleted file mode 100644 index 01295ba..0000000 --- a/volvox/src/test/java/it/cavallium/ExampleResourceTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package it.cavallium; - -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Test; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.is; - -@QuarkusTest -public class ExampleResourceTest { - - @Test - public void testHelloEndpoint() { - given().when().get("/hello").then().statusCode(200).body(is("Hello RESTEasy Reactive")); - } - -} \ No newline at end of file diff --git a/volvox/src/test/java/it/cavallium/NativeExampleResourceIT.java b/volvox/src/test/java/it/cavallium/NativeExampleResourceIT.java deleted file mode 100644 index 7c6541f..0000000 --- a/volvox/src/test/java/it/cavallium/NativeExampleResourceIT.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.cavallium; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -public class NativeExampleResourceIT extends ExampleResourceTest { - - // Execute the same tests but in native mode. -} \ No newline at end of file